mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-07-27 21:02:23 +00:00
add filament_extruder_map (#148)
This commit is contained in:
@@ -344,6 +344,9 @@ public:
|
||||
// Set a single vector item from either a scalar option or the first value of a vector option.vector of ConfigOptions.
|
||||
// This function is useful to split values from multiple extrder / filament settings into separate configurations.
|
||||
virtual void set_at(const ConfigOption *rhs, size_t i, size_t j) = 0;
|
||||
// SM Orca: Copy a single element from source vector at src_idx to this vector at dst_idx
|
||||
// This function is useful for applying physical extruder mapping to filament parameters
|
||||
virtual void set_at(const ConfigOptionVectorBase* source, size_t dst_idx, size_t src_idx) = 0;
|
||||
// Resize the vector of values, copy the newly added values from opt_default if provided.
|
||||
virtual void resize(size_t n, const ConfigOption *opt_default = nullptr) = 0;
|
||||
// Clear the values vector.
|
||||
@@ -431,6 +434,26 @@ public:
|
||||
throw ConfigurationError("ConfigOptionVector::set_at(): Assigning an incompatible type");
|
||||
}
|
||||
|
||||
// SM Orca: Copy a single element from source vector at src_idx to this vector at dst_idx
|
||||
// Used for applying physical extruder mapping to filament parameters
|
||||
void set_at(const ConfigOptionVectorBase* source, size_t dst_idx, size_t src_idx) override
|
||||
{
|
||||
auto* src_typed = dynamic_cast<const ConfigOptionVector<T>*>(source);
|
||||
if (!src_typed || src_idx >= src_typed->size() || dst_idx >= this->size())
|
||||
return;
|
||||
|
||||
// Handle nullable vectors - only copy if source value is not nil
|
||||
if (this->nullable() && src_typed->nullable()) {
|
||||
if (!src_typed->is_nil(src_idx)) {
|
||||
this->values[dst_idx] = src_typed->values[src_idx];
|
||||
}
|
||||
} else if (!src_typed->nullable()) {
|
||||
// Source is not nullable, always copy
|
||||
this->values[dst_idx] = src_typed->values[src_idx];
|
||||
}
|
||||
// If source is nullable and value is nil, don't copy (keep existing value)
|
||||
}
|
||||
|
||||
const T& get_at(size_t i) const
|
||||
{
|
||||
assert(! this->values.empty());
|
||||
|
||||
@@ -6,13 +6,14 @@ namespace Slic3r {
|
||||
double Extruder::m_share_E = 0.;
|
||||
double Extruder::m_share_retracted = 0.;
|
||||
|
||||
Extruder::Extruder(unsigned int id, GCodeConfig *config, bool share_extruder) :
|
||||
Extruder::Extruder(unsigned int id, unsigned int physical_extruder_id, GCodeConfig *config, bool share_extruder) :
|
||||
m_id(id),
|
||||
m_physical_extruder_id(physical_extruder_id),
|
||||
m_config(config),
|
||||
m_share_extruder(share_extruder)
|
||||
{
|
||||
reset();
|
||||
|
||||
|
||||
// cache values that are going to be called often
|
||||
m_e_per_mm3 = this->filament_flow_ratio();
|
||||
m_e_per_mm3 /= this->filament_crossection();
|
||||
@@ -157,24 +158,25 @@ double Extruder::filament_flow_ratio() const
|
||||
}
|
||||
|
||||
// Return a "retract_before_wipe" percentage as a factor clamped to <0, 1>
|
||||
// SM Orca: 回抽相关参数是挤出机属性,使用 m_physical_extruder_id
|
||||
double Extruder::retract_before_wipe() const
|
||||
{
|
||||
return std::min(1., std::max(0., m_config->retract_before_wipe.get_at(m_id) * 0.01));
|
||||
return std::min(1., std::max(0., m_config->retract_before_wipe.get_at(m_physical_extruder_id) * 0.01));
|
||||
}
|
||||
|
||||
double Extruder::retraction_length() const
|
||||
{
|
||||
return m_config->retraction_length.get_at(m_id);
|
||||
return m_config->retraction_length.get_at(m_physical_extruder_id);
|
||||
}
|
||||
|
||||
double Extruder::retract_lift() const
|
||||
{
|
||||
return m_config->z_hop.get_at(m_id);
|
||||
return m_config->z_hop.get_at(m_physical_extruder_id);
|
||||
}
|
||||
|
||||
int Extruder::retract_speed() const
|
||||
{
|
||||
return int(floor(m_config->retraction_speed.get_at(m_id)+0.5));
|
||||
return int(floor(m_config->retraction_speed.get_at(m_physical_extruder_id)+0.5));
|
||||
}
|
||||
|
||||
bool Extruder::use_firmware_retraction() const
|
||||
@@ -184,28 +186,28 @@ bool Extruder::use_firmware_retraction() const
|
||||
|
||||
int Extruder::deretract_speed() const
|
||||
{
|
||||
int speed = int(floor(m_config->deretraction_speed.get_at(m_id)+0.5));
|
||||
int speed = int(floor(m_config->deretraction_speed.get_at(m_physical_extruder_id)+0.5));
|
||||
return (speed > 0) ? speed : this->retract_speed();
|
||||
}
|
||||
|
||||
double Extruder::retract_restart_extra() const
|
||||
{
|
||||
return m_config->retract_restart_extra.get_at(m_id);
|
||||
return m_config->retract_restart_extra.get_at(m_physical_extruder_id);
|
||||
}
|
||||
|
||||
double Extruder::retract_length_toolchange() const
|
||||
{
|
||||
return m_config->retract_length_toolchange.get_at(m_id);
|
||||
return m_config->retract_length_toolchange.get_at(m_physical_extruder_id);
|
||||
}
|
||||
|
||||
double Extruder::retract_restart_extra_toolchange() const
|
||||
{
|
||||
return m_config->retract_restart_extra_toolchange.get_at(m_id);
|
||||
return m_config->retract_restart_extra_toolchange.get_at(m_physical_extruder_id);
|
||||
}
|
||||
|
||||
double Extruder::travel_slope() const
|
||||
{
|
||||
return m_config->travel_slope.get_at(m_id) * PI / 180;
|
||||
return m_config->travel_slope.get_at(m_physical_extruder_id) * PI / 180;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,7 +11,8 @@ class GCodeConfig;
|
||||
class Extruder
|
||||
{
|
||||
public:
|
||||
Extruder(unsigned int id, GCodeConfig *config, bool share_extruder);
|
||||
// SM Orca: 添加 physical_extruder_id 参数用于支持耗材-挤出机映射
|
||||
Extruder(unsigned int id, unsigned int physical_extruder_id, GCodeConfig *config, bool share_extruder);
|
||||
virtual ~Extruder() {}
|
||||
|
||||
void reset() {
|
||||
@@ -28,6 +29,8 @@ public:
|
||||
}
|
||||
|
||||
unsigned int id() const { return m_id; }
|
||||
// SM Orca: 获取物理挤出机ID
|
||||
unsigned int physical_extruder_id() const { return m_physical_extruder_id; }
|
||||
|
||||
double extrude(double dE);
|
||||
double retract(double length, double restart_extra);
|
||||
@@ -75,12 +78,14 @@ public:
|
||||
|
||||
private:
|
||||
// Private constructor to create a key for a search in std::set.
|
||||
Extruder(unsigned int id) : m_id(id) {}
|
||||
Extruder(unsigned int id) : m_id(id), m_physical_extruder_id(id) {}
|
||||
|
||||
// Reference to GCodeWriter instance owned by GCodeWriter.
|
||||
GCodeConfig *m_config;
|
||||
// Print-wide global ID of this extruder.
|
||||
// Print-wide global ID of this extruder (filament index).
|
||||
unsigned int m_id;
|
||||
// SM Orca: 物理挤出机ID,用于查询挤出机属性(温度、回抽等)
|
||||
unsigned int m_physical_extruder_id;
|
||||
// Current state of the extruder axis, may be resetted if use_relative_e_distances.
|
||||
double m_E;
|
||||
// Current state of the extruder tachometer, used to output the extruded_volume() and used_filament() statistics.
|
||||
|
||||
@@ -213,42 +213,93 @@ double Flow::mm3_per_mm() const
|
||||
|
||||
Flow support_material_flow(const PrintObject *object, float layer_height)
|
||||
{
|
||||
// SM Orca: 使用物理挤出机的喷嘴直径
|
||||
int filament_idx = object->config().support_filament - 1;
|
||||
int physical_extruder = object->print()->get_physical_extruder(filament_idx);
|
||||
|
||||
// SM Orca: 日志 - 配置数组访问边界检查
|
||||
const auto& nozzle_diameter_config = object->print()->config().nozzle_diameter;
|
||||
size_t array_size = nozzle_diameter_config.values.size();
|
||||
BOOST_LOG_TRIVIAL(info) << "Flow::support_material_flow: filament_idx=" << filament_idx
|
||||
<< " physical_extruder=" << physical_extruder
|
||||
<< " nozzle_diameter array_size=" << array_size
|
||||
<< " access_index=" << physical_extruder
|
||||
<< (physical_extruder >= (int)array_size ? " [POTENTIAL_OUT_OF_BOUNDS!]" : " [OK]");
|
||||
|
||||
return Flow::new_from_config_width(
|
||||
frSupportMaterial,
|
||||
// The width parameter accepted by new_from_config_width is of type ConfigOptionFloatOrPercent, the Flow class takes care of the percent to value substitution.
|
||||
(object->config().support_line_width.value > 0) ? object->config().support_line_width : object->config().line_width,
|
||||
// if object->config().support_filament == 0 (which means to not trigger tool change, but use the current extruder instead), get_at will return the 0th component.
|
||||
float(object->print()->config().nozzle_diameter.get_at(object->config().support_filament-1)),
|
||||
float(object->print()->config().nozzle_diameter.get_at(physical_extruder)),
|
||||
(layer_height > 0.f) ? layer_height : float(object->config().layer_height.value));
|
||||
}
|
||||
//BBS
|
||||
Flow support_transition_flow(const PrintObject* object)
|
||||
{
|
||||
//BBS: support transition of tree support is bridge flow
|
||||
float dmr = float(object->print()->config().nozzle_diameter.get_at(object->config().support_filament - 1));
|
||||
// SM Orca: 使用物理挤出机的喷嘴直径
|
||||
int filament_idx = object->config().support_filament - 1;
|
||||
int physical_extruder = object->print()->get_physical_extruder(filament_idx);
|
||||
|
||||
// SM Orca: 日志 - 配置数组访问边界检查
|
||||
const auto& nozzle_diameter_config = object->print()->config().nozzle_diameter;
|
||||
size_t array_size = nozzle_diameter_config.values.size();
|
||||
BOOST_LOG_TRIVIAL(info) << "Flow::support_transition_flow: filament_idx=" << filament_idx
|
||||
<< " physical_extruder=" << physical_extruder
|
||||
<< " nozzle_diameter array_size=" << array_size
|
||||
<< " access_index=" << physical_extruder
|
||||
<< (physical_extruder >= (int)array_size ? " [POTENTIAL_OUT_OF_BOUNDS!]" : " [OK]");
|
||||
|
||||
float dmr = float(object->print()->config().nozzle_diameter.get_at(physical_extruder));
|
||||
return Flow::bridging_flow(dmr, dmr);
|
||||
}
|
||||
|
||||
Flow support_material_1st_layer_flow(const PrintObject *object, float layer_height)
|
||||
{
|
||||
// SM Orca: 使用物理挤出机的喷嘴直径
|
||||
int filament_idx = object->config().support_filament - 1;
|
||||
int physical_extruder = object->print()->get_physical_extruder(filament_idx);
|
||||
const PrintConfig &print_config = object->print()->config();
|
||||
|
||||
// SM Orca: 日志 - 配置数组访问边界检查
|
||||
size_t array_size = print_config.nozzle_diameter.values.size();
|
||||
BOOST_LOG_TRIVIAL(info) << "Flow::support_material_1st_layer_flow: filament_idx=" << filament_idx
|
||||
<< " physical_extruder=" << physical_extruder
|
||||
<< " nozzle_diameter array_size=" << array_size
|
||||
<< " access_index=" << physical_extruder
|
||||
<< (physical_extruder >= (int)array_size ? " [POTENTIAL_OUT_OF_BOUNDS!]" : " [OK]");
|
||||
|
||||
const auto &width = (print_config.initial_layer_line_width.value > 0) ? print_config.initial_layer_line_width : object->config().support_line_width;
|
||||
return Flow::new_from_config_width(
|
||||
frSupportMaterial,
|
||||
// The width parameter accepted by new_from_config_width is of type ConfigOptionFloatOrPercent, the Flow class takes care of the percent to value substitution.
|
||||
(width.value > 0) ? width : object->config().line_width,
|
||||
float(print_config.nozzle_diameter.get_at(object->config().support_filament-1)),
|
||||
float(print_config.nozzle_diameter.get_at(physical_extruder)),
|
||||
(layer_height > 0.f) ? layer_height : float(print_config.initial_layer_print_height.value));
|
||||
}
|
||||
|
||||
Flow support_material_interface_flow(const PrintObject *object, float layer_height)
|
||||
{
|
||||
// SM Orca: 使用物理挤出机的喷嘴直径
|
||||
int filament_idx = object->config().support_interface_filament - 1;
|
||||
int physical_extruder = object->print()->get_physical_extruder(filament_idx);
|
||||
|
||||
// SM Orca: 日志 - 配置数组访问边界检查
|
||||
const auto& nozzle_diameter_config = object->print()->config().nozzle_diameter;
|
||||
size_t array_size = nozzle_diameter_config.values.size();
|
||||
BOOST_LOG_TRIVIAL(info) << "Flow::support_material_interface_flow: filament_idx=" << filament_idx
|
||||
<< " physical_extruder=" << physical_extruder
|
||||
<< " nozzle_diameter array_size=" << array_size
|
||||
<< " access_index=" << physical_extruder
|
||||
<< (physical_extruder >= (int)array_size ? " [POTENTIAL_OUT_OF_BOUNDS!]" : " [OK]");
|
||||
|
||||
return Flow::new_from_config_width(
|
||||
frSupportMaterialInterface,
|
||||
// The width parameter accepted by new_from_config_width is of type ConfigOptionFloatOrPercent, the Flow class takes care of the percent to value substitution.
|
||||
(object->config().support_line_width > 0) ? object->config().support_line_width : object->config().line_width,
|
||||
// if object->config().support_interface_filament == 0 (which means to not trigger tool change, but use the current extruder instead), get_at will return the 0th component.
|
||||
float(object->print()->config().nozzle_diameter.get_at(object->config().support_interface_filament-1)),
|
||||
float(object->print()->config().nozzle_diameter.get_at(physical_extruder)),
|
||||
(layer_height > 0.f) ? layer_height : float(object->config().layer_height.value));
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -114,7 +114,7 @@ private:
|
||||
std::string append_tcr2(GCode &gcodegen, const WipeTower::ToolChangeResult &tcr, int new_extruder_id, double z = -1.) const;
|
||||
|
||||
// Postprocesses gcode: rotates and moves G1 extrusions and returns result
|
||||
std::string post_process_wipe_tower_moves(const WipeTower::ToolChangeResult& tcr, const Vec2f& translation, float angle) const;
|
||||
std::string post_process_wipe_tower_moves(GCode& gcodegen, const WipeTower::ToolChangeResult& tcr, const Vec2f& translation, float angle) const;
|
||||
// Left / right edges of the wipe tower, for the planning of wipe moves.
|
||||
const float m_left;
|
||||
const float m_right;
|
||||
@@ -197,6 +197,9 @@ public:
|
||||
//BBS: set offset for gcode writer
|
||||
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); }
|
||||
|
||||
// Exported for the helper classes (OozePrevention, Wipe) and for the Perl binding for unit tests.
|
||||
const Vec2d& origin() const { return m_origin; }
|
||||
void set_origin(const Vec2d &pointf);
|
||||
|
||||
@@ -526,9 +526,18 @@ void GCodeProcessor::UsedFilaments::process_role_cache(GCodeProcessor* processor
|
||||
if (role_cache != 0.0f) {
|
||||
std::pair<double, double> filament = { 0.0f, 0.0f };
|
||||
|
||||
double s = PI * sqr(0.5 * processor->m_result.filament_diameters[processor->m_extruder_id]);
|
||||
// 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();
|
||||
|
||||
float density = (static_cast<size_t>(processor->m_extruder_id) < processor->m_result.filament_densities.size())
|
||||
? processor->m_result.filament_densities[processor->m_extruder_id]
|
||||
: processor->m_result.filament_densities.back();
|
||||
|
||||
double s = PI * sqr(0.5 * diameter);
|
||||
filament.first = role_cache / s * 0.001;
|
||||
filament.second = role_cache * processor->m_result.filament_densities[processor->m_extruder_id] * 0.001;
|
||||
filament.second = role_cache * density * 0.001;
|
||||
|
||||
ExtrusionRole active_role = processor->m_extrusion_role;
|
||||
if (filaments_per_role.find(active_role) != filaments_per_role.end()) {
|
||||
@@ -556,6 +565,25 @@ 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() << ")";
|
||||
}
|
||||
}
|
||||
|
||||
moves = std::vector<GCodeProcessorResult::MoveVertex>();
|
||||
printable_area = Pointfs();
|
||||
//BBS: add bed exclude area
|
||||
@@ -567,10 +595,22 @@ void GCodeProcessorResult::reset() {
|
||||
timelapse_warning_code = 0;
|
||||
printable_height = 0.0f;
|
||||
settings_ids.reset();
|
||||
extruders_count = 0;
|
||||
|
||||
// SM Orca: 恢复extruders_count为合理的值
|
||||
extruders_count = saved_count;
|
||||
extruder_colors = std::vector<std::string>();
|
||||
filament_diameters = std::vector<float>(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DIAMETER);
|
||||
filament_densities = std::vector<float>(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DENSITY);
|
||||
|
||||
// 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 << ")";
|
||||
|
||||
custom_gcode_per_print_z = std::vector<CustomGCode::Item>();
|
||||
spiral_vase_layers = std::vector<std::pair<float, std::pair<size_t, size_t>>>();
|
||||
time = 0;
|
||||
@@ -583,6 +623,25 @@ 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() << ")";
|
||||
}
|
||||
}
|
||||
|
||||
moves.clear();
|
||||
lines_ends.clear();
|
||||
printable_area = Pointfs();
|
||||
@@ -596,13 +655,23 @@ void GCodeProcessorResult::reset() {
|
||||
timelapse_warning_code = 0;
|
||||
printable_height = 0.0f;
|
||||
settings_ids.reset();
|
||||
extruders_count = 0;
|
||||
backtrace_enabled = false;
|
||||
extruder_colors = std::vector<std::string>();
|
||||
filament_diameters = std::vector<float>(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DIAMETER);
|
||||
required_nozzle_HRC = std::vector<int>(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_HRC);
|
||||
filament_densities = std::vector<float>(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DENSITY);
|
||||
filament_costs = std::vector<float>(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_COST);
|
||||
|
||||
// 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);
|
||||
@@ -719,6 +788,45 @@ 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) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "SM Orca: filament_density has "
|
||||
<< config.filament_density.values.size() << " values, expected " << extruders_count
|
||||
<< " (will use fallback values)";
|
||||
}
|
||||
|
||||
if (config.filament_cost.values.size() < extruders_count) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "SM Orca: filament_cost has "
|
||||
<< config.filament_cost.values.size() << " values, expected " << extruders_count
|
||||
<< " (will use fallback values)";
|
||||
}
|
||||
|
||||
if (config.nozzle_temperature.values.size() < extruders_count) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "SM Orca: nozzle_temperature has "
|
||||
<< config.nozzle_temperature.values.size() << " values, expected " << extruders_count
|
||||
<< " (will use fallback values)";
|
||||
}
|
||||
|
||||
// 验证映射表有效性
|
||||
if (!m_filament_extruder_map.empty()) {
|
||||
for (size_t i = 0; i < extruders_count; ++i) {
|
||||
int physical_extruder = get_physical_extruder(i);
|
||||
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
|
||||
<< " (valid range: 0-" << (physical_extruder_count - 1) << ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_extruder_offsets.resize(extruders_count);
|
||||
m_extruder_colors.resize(extruders_count);
|
||||
m_result.filament_diameters.resize(extruders_count);
|
||||
@@ -731,20 +839,103 @@ void GCodeProcessor::apply_config(const PrintConfig& config)
|
||||
m_extruder_temps_first_layer_config.resize(extruders_count);
|
||||
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();
|
||||
size_t temp_initial_count = config.nozzle_temperature_initial_layer.values.size();
|
||||
size_t temp_count = config.nozzle_temperature.values.size();
|
||||
size_t hrc_count = config.required_nozzle_HRC.values.size();
|
||||
size_t vitrification_count = config.temperature_vitrification.values.size();
|
||||
|
||||
for (size_t i = 0; i < extruders_count; ++ i) {
|
||||
m_extruder_offsets[i] = to_3d(config.extruder_offset.get_at(i).cast<float>().eval(), 0.f);
|
||||
// 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
|
||||
<< " (valid range: 0-" << (physical_extruder_count - 1) << ")";
|
||||
// 使用filament index作为fallback(1:1映射),如果也越界则使用0
|
||||
physical_extruder = (i < physical_extruder_count) ? static_cast<int>(i) : 0;
|
||||
BOOST_LOG_TRIVIAL(error) << " SM Orca: Using fallback physical extruder " << physical_extruder;
|
||||
}
|
||||
|
||||
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);
|
||||
m_extruder_temps_first_layer_config[i] = static_cast<int>(config.nozzle_temperature_initial_layer.get_at(i));
|
||||
m_extruder_temps_config[i] = static_cast<int>(config.nozzle_temperature.get_at(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));
|
||||
} else {
|
||||
int fallback = temp_initial_count > 0 ?
|
||||
static_cast<int>(config.nozzle_temperature_initial_layer.get_at(temp_initial_count - 1)) : 210;
|
||||
m_extruder_temps_first_layer_config[i] = fallback;
|
||||
BOOST_LOG_TRIVIAL(warning) << "SM Orca: Filament " << i << " (physical extruder " << physical_extruder << ") initial layer temperature not configured, using " << fallback;
|
||||
}
|
||||
|
||||
if (physical_extruder < static_cast<int>(temp_count)) {
|
||||
m_extruder_temps_config[i] = static_cast<int>(config.nozzle_temperature.get_at(physical_extruder));
|
||||
} else {
|
||||
int fallback = temp_count > 0 ?
|
||||
static_cast<int>(config.nozzle_temperature.get_at(temp_count - 1)) : 210;
|
||||
m_extruder_temps_config[i] = fallback;
|
||||
BOOST_LOG_TRIVIAL(warning) << "SM Orca: Filament " << i << " (physical extruder " << physical_extruder << ") temperature not configured, using " << fallback;
|
||||
}
|
||||
|
||||
if (m_extruder_temps_config[i] == 0) {
|
||||
// This means the value should be ignored and first layer temp should be used.
|
||||
m_extruder_temps_config[i] = m_extruder_temps_first_layer_config[i];
|
||||
}
|
||||
m_result.filament_diameters[i] = static_cast<float>(config.filament_diameter.get_at(i));
|
||||
m_result.required_nozzle_HRC[i] = static_cast<int>(config.required_nozzle_HRC.get_at(i));
|
||||
m_result.filament_densities[i] = static_cast<float>(config.filament_density.get_at(i));
|
||||
m_result.filament_vitrification_temperature[i] = static_cast<float>(config.temperature_vitrification.get_at(i));
|
||||
m_result.filament_costs[i] = static_cast<float>(config.filament_cost.get_at(i));
|
||||
|
||||
// SM Orca: 安全读取直径(使用最后有效值作为回退)
|
||||
if (i < diameter_count) {
|
||||
m_result.filament_diameters[i] = static_cast<float>(config.filament_diameter.get_at(i));
|
||||
} else {
|
||||
float fallback = diameter_count > 0 ?
|
||||
static_cast<float>(config.filament_diameter.get_at(diameter_count - 1)) : 1.75f;
|
||||
m_result.filament_diameters[i] = fallback;
|
||||
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 {
|
||||
int fallback = hrc_count > 0 ?
|
||||
static_cast<int>(config.required_nozzle_HRC.get_at(hrc_count - 1)) : 0;
|
||||
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 {
|
||||
float fallback = density_count > 0 ?
|
||||
static_cast<float>(config.filament_density.get_at(density_count - 1)) : 1.25f;
|
||||
m_result.filament_densities[i] = fallback;
|
||||
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 {
|
||||
int fallback = vitrification_count > 0 ?
|
||||
static_cast<int>(config.temperature_vitrification.get_at(vitrification_count - 1)) : 0;
|
||||
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 {
|
||||
m_result.filament_costs[i] = 0.0f;
|
||||
BOOST_LOG_TRIVIAL(warning) << "SM Orca: Filament " << i << " cost not configured, using 0.0";
|
||||
}
|
||||
}
|
||||
|
||||
if (m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware || m_flavor == gcfKlipper || m_flavor == gcfRepRapFirmware) {
|
||||
@@ -858,24 +1049,39 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
||||
|
||||
const ConfigOptionFloats* filament_diameters = config.option<ConfigOptionFloats>("filament_diameter");
|
||||
if (filament_diameters != nullptr) {
|
||||
m_result.filament_diameters.clear();
|
||||
m_result.filament_diameters.resize(filament_diameters->values.size());
|
||||
for (size_t i = 0; i < filament_diameters->values.size(); ++i) {
|
||||
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) {
|
||||
m_result.filament_diameters[i] = last_value;
|
||||
BOOST_LOG_TRIVIAL(debug) << "SM Orca: Filament " << i
|
||||
<< " diameter not in config, using last value " << last_value << "mm";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SM Orca: 确保数组大小正确(移除原有的回退逻辑,因为已经在上面处理了)
|
||||
if (m_result.filament_diameters.size() < m_result.extruders_count) {
|
||||
for (size_t i = m_result.filament_diameters.size(); i < m_result.extruders_count; ++i) {
|
||||
m_result.filament_diameters.emplace_back(DEFAULT_FILAMENT_DIAMETER);
|
||||
}
|
||||
m_result.filament_diameters.resize(m_result.extruders_count, DEFAULT_FILAMENT_DIAMETER);
|
||||
}
|
||||
|
||||
const ConfigOptionInts *filament_HRC = config.option<ConfigOptionInts>("required_nozzle_HRC");
|
||||
if (filament_HRC != nullptr) {
|
||||
m_result.required_nozzle_HRC.clear();
|
||||
m_result.required_nozzle_HRC.resize(filament_HRC->values.size());
|
||||
for (size_t i = 0; i < filament_HRC->values.size(); ++i) { m_result.required_nozzle_HRC[i] = static_cast<float>(filament_HRC->values[i]); }
|
||||
for (size_t i = 0; i < filament_HRC->values.size(); ++i) { m_result.required_nozzle_HRC[i] = static_cast<int>(filament_HRC->values[i]); }
|
||||
}
|
||||
|
||||
if (m_result.required_nozzle_HRC.size() < m_result.extruders_count) {
|
||||
@@ -885,43 +1091,86 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
||||
|
||||
const ConfigOptionFloats* filament_densities = config.option<ConfigOptionFloats>("filament_density");
|
||||
if (filament_densities != nullptr) {
|
||||
m_result.filament_densities.clear();
|
||||
m_result.filament_densities.resize(filament_densities->values.size());
|
||||
for (size_t i = 0; i < filament_densities->values.size(); ++i) {
|
||||
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) {
|
||||
m_result.filament_densities[i] = last_value;
|
||||
BOOST_LOG_TRIVIAL(debug) << "SM Orca: Filament " << i
|
||||
<< " density not in config, using last value " << last_value << " g/cm³";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SM Orca: 确保数组大小正确
|
||||
if (m_result.filament_densities.size() < m_result.extruders_count) {
|
||||
for (size_t i = m_result.filament_densities.size(); i < m_result.extruders_count; ++i) {
|
||||
m_result.filament_densities.emplace_back(DEFAULT_FILAMENT_DENSITY);
|
||||
}
|
||||
m_result.filament_densities.resize(m_result.extruders_count, DEFAULT_FILAMENT_DENSITY);
|
||||
}
|
||||
|
||||
//BBS
|
||||
const ConfigOptionFloats* filament_costs = config.option<ConfigOptionFloats>("filament_cost");
|
||||
if (filament_costs != nullptr) {
|
||||
m_result.filament_costs.clear();
|
||||
m_result.filament_costs.resize(filament_costs->values.size());
|
||||
for (size_t i = 0; i < filament_costs->values.size(); ++i)
|
||||
m_result.filament_costs[i]=static_cast<float>(filament_costs->values[i]);
|
||||
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;
|
||||
BOOST_LOG_TRIVIAL(debug) << "SM Orca: Filament " << i
|
||||
<< " cost not in config, using default " << DEFAULT_FILAMENT_COST;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (size_t i = m_result.filament_costs.size(); i < m_result.extruders_count; ++i) {
|
||||
m_result.filament_costs.emplace_back(DEFAULT_FILAMENT_COST);
|
||||
|
||||
// SM Orca: 确保数组大小正确
|
||||
if (m_result.filament_costs.size() < m_result.extruders_count) {
|
||||
m_result.filament_costs.resize(m_result.extruders_count, DEFAULT_FILAMENT_COST);
|
||||
}
|
||||
|
||||
//BBS
|
||||
const ConfigOptionInts* filament_vitrification_temperature = config.option<ConfigOptionInts>("temperature_vitrification");
|
||||
if (filament_vitrification_temperature != nullptr) {
|
||||
m_result.filament_vitrification_temperature.clear();
|
||||
m_result.filament_vitrification_temperature.resize(filament_vitrification_temperature->values.size());
|
||||
for (size_t i = 0; i < filament_vitrification_temperature->values.size(); ++i) {
|
||||
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]);
|
||||
}
|
||||
}
|
||||
if (m_result.filament_vitrification_temperature.size() < m_result.extruders_count) {
|
||||
for (size_t i = m_result.filament_vitrification_temperature.size(); i < m_result.extruders_count; ++i) {
|
||||
m_result.filament_vitrification_temperature.emplace_back(DEFAULT_FILAMENT_VITRIFICATION_TEMPERATURE);
|
||||
|
||||
// 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) {
|
||||
m_result.filament_vitrification_temperature[i] = last_value;
|
||||
BOOST_LOG_TRIVIAL(debug) << "SM Orca: Filament " << i
|
||||
<< " vitrification temperature not in config, using last value " << last_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -937,17 +1186,34 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
||||
}
|
||||
}
|
||||
else {
|
||||
m_extruder_offsets.resize(extruder_offset->values.size());
|
||||
for (size_t i = 0; i < extruder_offset->values.size(); ++i) {
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 只更新物理挤出机的offset
|
||||
for (size_t i = 0; i < physical_count && i < m_extruder_offsets.size(); ++i) {
|
||||
Vec2f offset = extruder_offset->values[i].cast<float>();
|
||||
m_extruder_offsets[i] = { offset(0), offset(1), 0.0f };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
m_extruder_offsets.emplace_back(DEFAULT_EXTRUDER_OFFSET);
|
||||
int physical_extruder = get_physical_extruder(i);
|
||||
// 如果映射的物理挤出机索引在有效范围内,复用它的offset
|
||||
if (physical_extruder >= 0 && physical_extruder < static_cast<int>(physical_count)) {
|
||||
m_extruder_offsets.emplace_back(m_extruder_offsets[physical_extruder]);
|
||||
BOOST_LOG_TRIVIAL(debug) << "Filament " << i << " using offset from physical extruder " << physical_extruder;
|
||||
} else {
|
||||
// 否则使用默认offset
|
||||
m_extruder_offsets.emplace_back(DEFAULT_EXTRUDER_OFFSET);
|
||||
BOOST_LOG_TRIVIAL(warning) << "Filament " << i << " using default offset (physical extruder " << physical_extruder << " out of range)";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1117,6 +1383,34 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
||||
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: "
|
||||
<< m_result.filament_diameters.size() << " != " << m_result.extruders_count;
|
||||
arrays_valid = false;
|
||||
}
|
||||
if (m_result.filament_densities.size() != m_result.extruders_count) {
|
||||
BOOST_LOG_TRIVIAL(error) << "SM Orca: CRITICAL - filament_densities size mismatch: "
|
||||
<< m_result.filament_densities.size() << " != " << m_result.extruders_count;
|
||||
arrays_valid = false;
|
||||
}
|
||||
if (m_result.filament_costs.size() != m_result.extruders_count) {
|
||||
BOOST_LOG_TRIVIAL(error) << "SM Orca: CRITICAL - filament_costs size mismatch: "
|
||||
<< m_result.filament_costs.size() << " != " << m_result.extruders_count;
|
||||
arrays_valid = false;
|
||||
}
|
||||
if (m_result.filament_vitrification_temperature.size() != m_result.extruders_count) {
|
||||
BOOST_LOG_TRIVIAL(error) << "SM Orca: CRITICAL - filament_vitrification_temperature size mismatch: "
|
||||
<< m_result.filament_vitrification_temperature.size() << " != " << m_result.extruders_count;
|
||||
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)
|
||||
@@ -1556,6 +1850,23 @@ 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])) {
|
||||
BOOST_LOG_TRIVIAL(error) << "SM Orca: Detected invalid m_start_position at line " << m_line_id
|
||||
<< " extruder=" << static_cast<int>(m_extruder_id)
|
||||
<< " m_start_position=(" << m_start_position[X] << ", " << m_start_position[Y] << ", " << m_start_position[Z] << ")"
|
||||
<< " m_end_position=(" << m_end_position[X] << ", " << m_end_position[Y] << ", " << m_end_position[Z] << ")";
|
||||
// 重置为原点,防止污染继续传播
|
||||
m_start_position[X] = std::isnan(m_start_position[X]) || std::isinf(m_start_position[X]) ? 0.0f : m_start_position[X];
|
||||
m_start_position[Y] = std::isnan(m_start_position[Y]) || std::isinf(m_start_position[Y]) ? 0.0f : m_start_position[Y];
|
||||
m_start_position[Z] = std::isnan(m_start_position[Z]) || std::isinf(m_start_position[Z]) ? 0.0f : m_start_position[Z];
|
||||
m_end_position[X] = std::isnan(m_end_position[X]) || std::isinf(m_end_position[X]) ? 0.0f : m_end_position[X];
|
||||
m_end_position[Y] = std::isnan(m_end_position[Y]) || std::isinf(m_end_position[Y]) ? 0.0f : m_end_position[Y];
|
||||
m_end_position[Z] = std::isnan(m_end_position[Z]) || std::isinf(m_end_position[Z]) ? 0.0f : m_end_position[Z];
|
||||
}
|
||||
|
||||
const std::string_view cmd = line.cmd();
|
||||
if (m_flavor == gcfKlipper)
|
||||
{
|
||||
@@ -2635,6 +2946,22 @@ 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])) {
|
||||
BOOST_LOG_TRIVIAL(error) << "SM Orca: Invalid m_end_position after G1 processing for extruder " << static_cast<int>(m_extruder_id)
|
||||
<< " m_end_position=(" << m_end_position[X] << ", " << m_end_position[Y] << ", " << m_end_position[Z] << ")"
|
||||
<< " m_start_position=(" << m_start_position[X] << ", " << m_start_position[Y] << ", " << m_start_position[Z] << ")"
|
||||
<< " m_origin=(" << m_origin[X] << ", " << m_origin[Y] << ", " << m_origin[Z] << ")"
|
||||
<< " has_X=" << line.has(X) << " has_Y=" << line.has(Y) << " has_Z=" << line.has(Z)
|
||||
<< " X_value=" << (line.has(X) ? line.value(X) : 0.0f)
|
||||
<< " Y_value=" << (line.has(Y) ? line.value(Y) : 0.0f)
|
||||
<< " Z_value=" << (line.has(Z) ? line.value(Z) : 0.0f)
|
||||
<< " positioning=" << (m_global_positioning_type == EPositioningType::Relative ? "relative" : "absolute")
|
||||
<< " units=" << (m_units == EUnits::Inches ? "inches" : "mm");
|
||||
}
|
||||
|
||||
// updates feedrate from line, if present
|
||||
if (line.has_f())
|
||||
m_feedrate = line.f() * MMMIN_TO_MMSEC;
|
||||
@@ -2698,13 +3025,35 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line, const std::o
|
||||
else if (m_extrusion_role == erExternalPerimeter)
|
||||
// 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)
|
||||
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
|
||||
<< ") for extruder " << m_extruder_id << ", using absolute value";
|
||||
ratio = std::abs(ratio);
|
||||
}
|
||||
|
||||
// cross section: circle
|
||||
m_width = static_cast<float>(m_result.filament_diameters[m_extruder_id]) * std::sqrt(delta_pos[E] / delta_xyz);
|
||||
m_width = diameter * std::sqrt(ratio);
|
||||
}
|
||||
else
|
||||
// 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
|
||||
<< " (E=" << delta_pos[E] << ", XYZ=" << delta_xyz << ")";
|
||||
m_width = DEFAULT_TOOLPATH_WIDTH;
|
||||
}
|
||||
|
||||
if (m_width == 0.0f)
|
||||
m_width = DEFAULT_TOOLPATH_WIDTH;
|
||||
|
||||
@@ -2960,6 +3309,7 @@ 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);
|
||||
@@ -2979,6 +3329,7 @@ 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
|
||||
@@ -2994,6 +3345,7 @@ 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);
|
||||
}
|
||||
|
||||
@@ -3086,6 +3438,23 @@ void GCodeProcessor::process_G2_G3(const GCodeReader::GCodeLine& line)
|
||||
for (unsigned char a = X; a <= E; ++a) {
|
||||
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])) {
|
||||
BOOST_LOG_TRIVIAL(error) << "SM Orca: Invalid m_end_position after G2/G3 processing for extruder " << static_cast<int>(m_extruder_id)
|
||||
<< " m_end_position=(" << m_end_position[X] << ", " << m_end_position[Y] << ", " << m_end_position[Z] << ")"
|
||||
<< " m_start_position=(" << m_start_position[X] << ", " << m_start_position[Y] << ", " << m_start_position[Z] << ")"
|
||||
<< " m_origin=(" << m_origin[X] << ", " << m_origin[Y] << ", " << m_origin[Z] << ")"
|
||||
<< " has_X=" << line.has(X) << " has_Y=" << line.has(Y) << " has_Z=" << line.has(Z)
|
||||
<< " X_value=" << (line.has(X) ? line.value(X) : 0.0f)
|
||||
<< " Y_value=" << (line.has(Y) ? line.value(Y) : 0.0f)
|
||||
<< " Z_value=" << (line.has(Z) ? line.value(Z) : 0.0f)
|
||||
<< " positioning=" << (m_global_positioning_type == EPositioningType::Relative ? "relative" : "absolute")
|
||||
<< " units=" << (m_units == EUnits::Inches ? "inches" : "mm");
|
||||
}
|
||||
|
||||
//BBS: G2 G3 line but has no I and J axis, invalid G code format
|
||||
if (!line.has(I) && !line.has(J))
|
||||
return;
|
||||
@@ -3178,13 +3547,35 @@ void GCodeProcessor::process_G2_G3(const GCodeReader::GCodeLine& line)
|
||||
else if (m_extrusion_role == erExternalPerimeter)
|
||||
//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)
|
||||
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
|
||||
<< ") for extruder " << m_extruder_id << ", using absolute value";
|
||||
ratio = std::abs(ratio);
|
||||
}
|
||||
|
||||
//BBS: cross section: circle
|
||||
m_width = static_cast<float>(m_result.filament_diameters[m_extruder_id]) * std::sqrt(delta_pos[E] / delta_xyz);
|
||||
m_width = diameter * std::sqrt(ratio);
|
||||
}
|
||||
else
|
||||
//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
|
||||
<< " (E=" << delta_pos[E] << ", XYZ=" << delta_xyz << ")";
|
||||
m_width = DEFAULT_TOOLPATH_WIDTH;
|
||||
}
|
||||
|
||||
if (m_width == 0.0f)
|
||||
m_width = DEFAULT_TOOLPATH_WIDTH;
|
||||
|
||||
@@ -3395,6 +3786,7 @@ 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);
|
||||
@@ -3412,6 +3804,7 @@ 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
|
||||
@@ -3427,6 +3820,7 @@ 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);
|
||||
}
|
||||
|
||||
@@ -3472,17 +3866,21 @@ 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(m_extruder_id));
|
||||
g10.set(Axis::F, this->m_parser.config().retraction_speed.get_at(m_extruder_id) * 60);
|
||||
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);
|
||||
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(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);
|
||||
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);
|
||||
process_G1(g11);
|
||||
}
|
||||
|
||||
@@ -3574,12 +3972,26 @@ void GCodeProcessor::process_G92(const GCodeReader::GCodeLine& line)
|
||||
simulate_st_synchronize();
|
||||
|
||||
if (!any_found && !line.has_unknown_axis()) {
|
||||
// The G92 may be called for axes that PrusaSlicer does not recognize, for example see GH issue #3510,
|
||||
// The G92 may be called for axes that PrusaSlicer does not recognize, for example see GH issue #3510,
|
||||
// where G92 A0 B0 is called although the extruder axis is till E.
|
||||
for (unsigned char a = X; a <= E; ++a) {
|
||||
m_origin[a] = m_end_position[a];
|
||||
}
|
||||
}
|
||||
|
||||
// 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])) {
|
||||
BOOST_LOG_TRIVIAL(error) << "SM Orca: Invalid m_origin after G92 processing"
|
||||
<< " extruder=" << static_cast<int>(m_extruder_id)
|
||||
<< " m_origin=(" << m_origin[X] << ", " << m_origin[Y] << ", " << m_origin[Z] << ")"
|
||||
<< " m_end_position=(" << m_end_position[X] << ", " << m_end_position[Y] << ", " << m_end_position[Z] << ")";
|
||||
// 重置为0,防止污染继续传播
|
||||
m_origin[X] = std::isnan(m_origin[X]) || std::isinf(m_origin[X]) ? 0.0f : m_origin[X];
|
||||
m_origin[Y] = std::isnan(m_origin[Y]) || std::isinf(m_origin[Y]) ? 0.0f : m_origin[Y];
|
||||
m_origin[Z] = std::isnan(m_origin[Z]) || std::isinf(m_origin[Z]) ? 0.0f : m_origin[Z];
|
||||
}
|
||||
}
|
||||
|
||||
void GCodeProcessor::process_M1(const GCodeReader::GCodeLine& line)
|
||||
@@ -4045,12 +4457,54 @@ void GCodeProcessor::run_post_process()
|
||||
double filament_total_cost = 0.0;
|
||||
|
||||
for (const auto& [id, volume] : m_result.print_statistics.total_volumes_per_extruder) {
|
||||
filament_mm[id] = volume / (static_cast<double>(M_PI) * sqr(0.5 * m_result.filament_diameters[id]));
|
||||
// SM Orca: 边界检查 - 确保id在有效范围内
|
||||
if (id >= m_result.filament_diameters.size() ||
|
||||
id >= m_result.filament_densities.size() ||
|
||||
id >= m_result.filament_costs.size()) {
|
||||
BOOST_LOG_TRIVIAL(error) << "SM Orca: Filament index " << id << " out of bounds (sizes: "
|
||||
<< "diameter=" << m_result.filament_diameters.size()
|
||||
<< ", density=" << m_result.filament_densities.size()
|
||||
<< ", cost=" << m_result.filament_costs.size() << "), skipping cost calculation";
|
||||
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";
|
||||
diameter = 1.75;
|
||||
}
|
||||
|
||||
if (density <= 0.0 || std::isnan(density)) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "SM Orca: Invalid filament density " << density
|
||||
<< " for filament " << id << ", using default 1.25 g/cm³";
|
||||
density = 1.25;
|
||||
}
|
||||
|
||||
if (cost < 0.0 || std::isnan(cost)) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "SM Orca: Invalid filament cost " << cost
|
||||
<< " for filament " << id << ", using 0.0";
|
||||
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;
|
||||
filament_g[id] = filament_cm3[id] * double(m_result.filament_densities[id]);
|
||||
filament_cost[id] = filament_g[id] * double(m_result.filament_costs[id]) * 0.001;
|
||||
filament_g[id] = filament_cm3[id] * density;
|
||||
filament_cost[id] = filament_g[id] * cost * 0.001;
|
||||
|
||||
filament_total_g += filament_g[id];
|
||||
filament_total_cost += filament_cost[id];
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "SM Orca: Filament " << id
|
||||
<< " - volume: " << volume << "mm³, length: " << filament_mm[id]
|
||||
<< "mm, weight: " << filament_g[id] << "g, cost: " << filament_cost[id];
|
||||
}
|
||||
|
||||
double total_g_wipe_tower = m_print->print_statistics().total_wipe_tower_filament;
|
||||
@@ -4771,6 +5225,11 @@ 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);
|
||||
|
||||
//BBS: apply plate's and extruder's offset to arc interpolation points
|
||||
if (path_type == EMovePathType::Arc_move_cw ||
|
||||
path_type == EMovePathType::Arc_move_ccw) {
|
||||
@@ -4779,7 +5238,40 @@ void GCodeProcessor::store_move_vertex(EMoveType type, EMovePathType path_type)
|
||||
Vec3f(m_interpolation_points[i].x() + m_x_offset,
|
||||
m_interpolation_points[i].y() + m_y_offset,
|
||||
m_processing_start_custom_gcode ? m_first_layer_height : m_interpolation_points[i].z()) +
|
||||
m_extruder_offsets[m_extruder_id];
|
||||
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 << ")";
|
||||
m_width = DEFAULT_TOOLPATH_WIDTH;
|
||||
}
|
||||
|
||||
if (std::isnan(m_height) || std::isinf(m_height)) {
|
||||
BOOST_LOG_TRIVIAL(error) << "SM Orca: Blocking invalid height: " << m_height
|
||||
<< " (extruder " << m_extruder_id << ")";
|
||||
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)
|
||||
+ extruder_offset;
|
||||
|
||||
if (std::isnan(final_position.x()) || std::isinf(final_position.x()) ||
|
||||
std::isnan(final_position.y()) || std::isinf(final_position.y()) ||
|
||||
std::isnan(final_position.z()) || std::isinf(final_position.z())) {
|
||||
BOOST_LOG_TRIVIAL(error) << "SM Orca: Invalid position calculated for extruder " << static_cast<int>(m_extruder_id)
|
||||
<< " position=(" << final_position.x() << ", " << final_position.y() << ", " << final_position.z() << ")"
|
||||
<< " m_end_position=(" << m_end_position[X] << ", " << m_end_position[Y] << ", " << m_end_position[Z] << ")"
|
||||
<< " offset=(" << m_x_offset << ", " << m_y_offset << ", " << m_z_offset << ")"
|
||||
<< " extruder_offset=(" << extruder_offset.x() << ", " << extruder_offset.y() << ", " << extruder_offset.z() << ")";
|
||||
// 使用不带offset的position作为fallback
|
||||
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);
|
||||
}
|
||||
|
||||
m_result.moves.push_back({
|
||||
@@ -4789,7 +5281,8 @@ 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
|
||||
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) + m_extruder_offsets[m_extruder_id],
|
||||
// SM Orca: 使用验证过的final_position
|
||||
final_position,
|
||||
static_cast<float>(m_end_position[E] - m_start_position[E]),
|
||||
m_feedrate,
|
||||
m_width,
|
||||
@@ -4802,6 +5295,7 @@ 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,
|
||||
});
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <optional>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
@@ -677,6 +678,8 @@ class Print;
|
||||
EPositioningType m_global_positioning_type;
|
||||
EPositioningType m_e_local_positioning_type;
|
||||
std::vector<Vec3f> m_extruder_offsets;
|
||||
// SM Orca: 耗材到物理挤出机的映射
|
||||
std::unordered_map<int, int> m_filament_extruder_map;
|
||||
GCodeFlavor m_flavor;
|
||||
float m_nozzle_volume;
|
||||
AxisCoords m_start_position; // mm
|
||||
@@ -776,6 +779,21 @@ class Print;
|
||||
|
||||
void apply_config(const PrintConfig& config);
|
||||
void set_print(Print* print) { m_print = print; }
|
||||
// SM Orca: 设置耗材到物理挤出机的映射
|
||||
void set_filament_extruder_map(const std::unordered_map<int, int>& map) {
|
||||
m_filament_extruder_map = map;
|
||||
}
|
||||
// SM Orca: 获取物理挤出机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;
|
||||
// SM Orca: 日志 - 映射查询
|
||||
BOOST_LOG_TRIVIAL(info) << "GCodeProcessor::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_identity]");
|
||||
return physical_extruder_id;
|
||||
}
|
||||
void enable_stealth_time_estimator(bool enabled);
|
||||
bool is_stealth_time_estimator_enabled() const {
|
||||
return m_time_processor.machines[static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Stealth)].enabled;
|
||||
|
||||
@@ -668,18 +668,20 @@ WipeTower::WipeTower(const PrintConfig& config, int plate_idx, Vec3d plate_origi
|
||||
|
||||
|
||||
|
||||
void WipeTower::set_extruder(size_t idx, const PrintConfig& config)
|
||||
void WipeTower::set_extruder(size_t idx, int physical_extruder, const PrintConfig& config)
|
||||
{
|
||||
//while (m_filpar.size() < idx+1) // makes sure the required element is in the vector
|
||||
m_filpar.push_back(FilamentParameters());
|
||||
|
||||
// SM Orca: 耗材属性使用 idx (filament index)
|
||||
m_filpar[idx].material = config.filament_type.get_at(idx);
|
||||
// m_filpar[idx].is_soluble = config.filament_soluble.get_at(idx);
|
||||
m_filpar[idx].is_soluble = config.wipe_tower_filament == 0 ? config.filament_soluble.get_at(idx) : (idx != size_t(config.wipe_tower_filament - 1));
|
||||
// BBS
|
||||
m_filpar[idx].is_support = config.filament_is_support.get_at(idx);
|
||||
m_filpar[idx].nozzle_temperature = config.nozzle_temperature.get_at(idx);
|
||||
m_filpar[idx].nozzle_temperature_initial_layer = config.nozzle_temperature_initial_layer.get_at(idx);
|
||||
// SM Orca: 温度是挤出机属性,使用 physical_extruder
|
||||
m_filpar[idx].nozzle_temperature = config.nozzle_temperature.get_at(physical_extruder);
|
||||
m_filpar[idx].nozzle_temperature_initial_layer = config.nozzle_temperature_initial_layer.get_at(physical_extruder);
|
||||
|
||||
// If this is a single extruder MM printer, we will use all the SE-specific config values.
|
||||
// Otherwise, the defaults will be used to turn off the SE stuff.
|
||||
@@ -698,14 +700,19 @@ void WipeTower::set_extruder(size_t idx, const PrintConfig& config)
|
||||
#endif
|
||||
|
||||
m_filpar[idx].filament_area = float((M_PI/4.f) * pow(config.filament_diameter.get_at(idx), 2)); // all extruders are assumed to have the same filament diameter at this point
|
||||
float nozzle_diameter = float(config.nozzle_diameter.get_at(idx));
|
||||
// SM Orca: 喷嘴直径是挤出机属性,使用 physical_extruder
|
||||
float nozzle_diameter = float(config.nozzle_diameter.get_at(physical_extruder));
|
||||
m_filpar[idx].nozzle_diameter = nozzle_diameter; // to be used in future with (non-single) multiextruder MM
|
||||
|
||||
float max_vol_speed = float(config.filament_max_volumetric_speed.get_at(idx));
|
||||
if (max_vol_speed!= 0.f)
|
||||
m_filpar[idx].max_e_speed = (max_vol_speed / filament_area());
|
||||
|
||||
m_perimeter_width = nozzle_diameter * Width_To_Nozzle_Ratio; // all extruders are now assumed to have the same diameter
|
||||
// SM Orca: Store per-filament perimeter width and also set the global one
|
||||
// Note: m_perimeter_width gets overwritten with each set_extruder() call
|
||||
// The brim should use m_filpar[0].perimeter_width for consistency
|
||||
m_filpar[idx].perimeter_width = nozzle_diameter * Width_To_Nozzle_Ratio;
|
||||
m_perimeter_width = m_filpar[idx].perimeter_width; // all extruders are now assumed to have the same diameter
|
||||
// BBS: remove useless config
|
||||
#if 0
|
||||
if (m_semm) {
|
||||
@@ -1305,7 +1312,10 @@ WipeTower::ToolChangeResult WipeTower::finish_layer(bool extrude_perimeter, bool
|
||||
}
|
||||
|
||||
// brim chamfer
|
||||
float spacing = m_perimeter_width - m_layer_height * float(1. - M_PI_4);
|
||||
// SM Orca: Use first filament's perimeter width for consistent brim spacing
|
||||
// The brim is generated once for the entire wipe tower and should use a consistent spacing
|
||||
float brim_perimeter_width = m_filpar.empty() ? m_perimeter_width : m_filpar[0].perimeter_width;
|
||||
float spacing = brim_perimeter_width - m_layer_height * float(1. - M_PI_4);
|
||||
// How many perimeters shall the brim have?
|
||||
int loops_num = (m_wipe_tower_brim_width + spacing / 2.f) / spacing;
|
||||
const float max_chamfer_width = 3.f;
|
||||
|
||||
@@ -144,7 +144,8 @@ public:
|
||||
|
||||
|
||||
// Set the extruder properties.
|
||||
void set_extruder(size_t idx, const PrintConfig& config);
|
||||
// SM Orca: 添加 physical_extruder 参数,用于支持耗材-挤出机映射
|
||||
void set_extruder(size_t idx, int physical_extruder, const PrintConfig& config);
|
||||
|
||||
// Appends into internal structure m_plan containing info about the future wipe tower
|
||||
// to be used before building begins. The entries must be added ordered in z.
|
||||
@@ -269,6 +270,8 @@ public:
|
||||
std::vector<float> ramming_speed;
|
||||
float nozzle_diameter;
|
||||
float filament_area;
|
||||
// SM Orca: Store per-filament perimeter width for correct brim generation
|
||||
float perimeter_width = 0.f;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -45,7 +45,9 @@ public:
|
||||
|
||||
|
||||
// Set the extruder properties.
|
||||
void set_extruder(size_t idx, const PrintConfig& config);
|
||||
// SM Orca: 添加 physical_extruder 参数,用于支持耗材-挤出机映射
|
||||
// idx: 耗材索引, physical_extruder: 物理挤出机索引
|
||||
void set_extruder(size_t idx, int physical_extruder, const PrintConfig& config);
|
||||
|
||||
// Appends into internal structure m_plan containing info about the future wipe tower
|
||||
// to be used before building begins. The entries must be added ordered in z.
|
||||
@@ -160,6 +162,8 @@ public:
|
||||
float filament_minimal_purge_on_wipe_tower = 0.f;
|
||||
float retract_length;
|
||||
float retract_speed;
|
||||
// SM Orca: Store per-filament perimeter width for correct brim generation
|
||||
float perimeter_width = 0.f;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
@@ -45,17 +45,26 @@ 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());
|
||||
for (unsigned int extruder_id : extruder_ids)
|
||||
m_extruders.emplace_back(Extruder(extruder_id, &this->config, config.single_extruder_multi_material.value));
|
||||
|
||||
// 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
|
||||
<< " -> physical_extruder_id=" << physical_extruder_id;
|
||||
m_extruders.emplace_back(Extruder(extruder_id, physical_extruder_id, &this->config, config.single_extruder_multi_material.value));
|
||||
}
|
||||
|
||||
/* we enable support for multiple extruder if any extruder greater than 0 is used
|
||||
(even if prints only uses that one) since we need to output Tx commands
|
||||
first extruder has index 0 */
|
||||
this->multiple_extruders = (*std::max_element(extruder_ids.begin(), extruder_ids.end())) > 0;
|
||||
BOOST_LOG_TRIVIAL(info) << "GCodeWriter::set_extruders: END - multiple_extruders=" << this->multiple_extruders;
|
||||
}
|
||||
|
||||
std::string GCodeWriter::preamble()
|
||||
@@ -454,6 +463,12 @@ 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; });
|
||||
assert(it_extruder != m_extruders.end() && it_extruder->id() == extruder_id);
|
||||
@@ -463,12 +478,16 @@ 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)
|
||||
gcode << " ; change extruder";
|
||||
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();
|
||||
}
|
||||
@@ -489,13 +508,21 @@ 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)
|
||||
<< " point=(" << point(0) << ", " << point(1) << ")"
|
||||
<< " comment=" << comment;
|
||||
}
|
||||
|
||||
m_pos(0) = point(0);
|
||||
m_pos(1) = point(1);
|
||||
|
||||
this->set_current_position_clear(true);
|
||||
//BBS: take plate offset into consider
|
||||
Vec2d point_on_plate = { point(0) - m_x_offset, point(1) - m_y_offset };
|
||||
|
||||
|
||||
GCodeG1Formatter w;
|
||||
w.emit_xy(point_on_plate);
|
||||
auto speed = m_is_first_layer
|
||||
@@ -709,11 +736,20 @@ 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)
|
||||
<< " point=(" << point(0) << ", " << point(1) << ")"
|
||||
<< " dE=" << dE
|
||||
<< " comment=" << comment;
|
||||
}
|
||||
|
||||
m_pos(0) = point(0);
|
||||
m_pos(1) = point(1);
|
||||
if(std::abs(dE) <= std::numeric_limits<double>::epsilon())
|
||||
force_no_extrusion = true;
|
||||
|
||||
|
||||
if (!force_no_extrusion)
|
||||
m_extruder->extrude(dE);
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "libslic3r.h"
|
||||
#include <string>
|
||||
#include <charconv>
|
||||
#include <unordered_map>
|
||||
#include "Extruder.hpp"
|
||||
#include "Point.hpp"
|
||||
#include "PrintConfig.hpp"
|
||||
@@ -119,6 +120,21 @@ public:
|
||||
void set_is_first_layer(bool bval) { m_is_first_layer = bval; }
|
||||
GCodeFlavor get_gcode_flavor() const { return config.gcode_flavor; }
|
||||
|
||||
// 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本身)
|
||||
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;
|
||||
// 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() << ")"
|
||||
<< (it != m_filament_extruder_map.end() ? " [from_map]" : " [default_identity]");
|
||||
return physical_extruder_id;
|
||||
}
|
||||
|
||||
// Returns whether this flavor supports separate print and travel acceleration.
|
||||
static bool supports_separate_travel_acceleration(GCodeFlavor flavor);
|
||||
private:
|
||||
@@ -170,6 +186,9 @@ public:
|
||||
double m_current_speed;
|
||||
bool m_is_first_layer = true;
|
||||
|
||||
// SM Orca: 耗材到物理挤出机的映射表(filament_idx -> physical_extruder_id)
|
||||
std::unordered_map<int, int> m_filament_extruder_map;
|
||||
|
||||
enum class Acceleration {
|
||||
Travel,
|
||||
Print
|
||||
|
||||
@@ -293,8 +293,6 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
|
||||
|| opt_key == "wipe_tower_no_sparse_layers"
|
||||
|| opt_key == "flush_volumes_matrix"
|
||||
|| opt_key == "prime_volume"
|
||||
|| opt_key == "prime_tower_brim_chamfer"
|
||||
|| opt_key == "prime_tower_brim_chamfer_max_width"
|
||||
|| opt_key == "flush_into_infill"
|
||||
|| opt_key == "flush_into_support"
|
||||
|| opt_key == "initial_layer_infill_speed"
|
||||
@@ -495,6 +493,44 @@ 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()
|
||||
{
|
||||
m_filament_extruder_map.clear();
|
||||
|
||||
// Get the number of physical extruders (number of nozzle_diameter entries)
|
||||
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!";
|
||||
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";
|
||||
|
||||
// Create mapping: filament_id -> physical_extruder_id
|
||||
// Mapping formula: physical_extruder = filament_id % physical_extruder_count
|
||||
// This allows using 8 filaments with 4 physical extruders:
|
||||
// filament 0,1,2,3 -> extruder 0,1,2,3
|
||||
// filament 4,5,6,7 -> extruder 0,1,2,3
|
||||
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
|
||||
{
|
||||
unsigned int instances = 0;
|
||||
@@ -506,8 +542,11 @@ unsigned int Print::num_object_instances() const
|
||||
double Print::max_allowed_layer_height() const
|
||||
{
|
||||
double nozzle_diameter_max = 0.;
|
||||
for (unsigned int extruder_id : this->extruders())
|
||||
nozzle_diameter_max = std::max(nozzle_diameter_max, m_config.nozzle_diameter.get_at(extruder_id));
|
||||
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));
|
||||
}
|
||||
return nozzle_diameter_max;
|
||||
}
|
||||
|
||||
@@ -1185,10 +1224,13 @@ 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
|
||||
double first_nozzle_diam = m_config.nozzle_diameter.get_at(extruders.front());
|
||||
// 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());
|
||||
for (const auto& extruder_idx : extruders) {
|
||||
double nozzle_diam = m_config.nozzle_diameter.get_at(extruder_idx);
|
||||
int physical_extruder = get_physical_extruder(extruder_idx);
|
||||
double nozzle_diam = m_config.nozzle_diameter.get_at(physical_extruder);
|
||||
double filament_diam = m_config.filament_diameter.get_at(extruder_idx);
|
||||
if (nozzle_diam - EPSILON > first_nozzle_diam || nozzle_diam + EPSILON < first_nozzle_diam
|
||||
|| std::abs((filament_diam - first_filament_diam) / first_filament_diam) > 0.1) {
|
||||
@@ -1294,7 +1336,9 @@ 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) {
|
||||
double dmr = m_config.nozzle_diameter.get_at(extruder_id);
|
||||
// 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);
|
||||
max_nozzle_diameter = std::max(max_nozzle_diameter, dmr);
|
||||
}
|
||||
@@ -1382,9 +1426,11 @@ 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 :
|
||||
m_config.nozzle_diameter.get_at(first_layer_extruder);
|
||||
m_config.nozzle_diameter.get_at(physical_extruder);
|
||||
} else {
|
||||
// if we don't have raft layers, any nozzle diameter is potentially used in first layer
|
||||
first_layer_min_nozzle_diameter = min_nozzle_diameter;
|
||||
@@ -1702,11 +1748,14 @@ 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(
|
||||
frPerimeter,
|
||||
// Flow::new_from_config_width takes care of the percent to value substitution
|
||||
width,
|
||||
(float)m_config.nozzle_diameter.get_at(m_print_regions.front()->config().wall_filament-1),
|
||||
(float)m_config.nozzle_diameter.get_at(physical_extruder),
|
||||
(float)this->skirt_first_layer_height());
|
||||
}
|
||||
|
||||
@@ -1721,11 +1770,14 @@ 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(
|
||||
frPerimeter,
|
||||
// Flow::new_from_config_width takes care of the percent to value substitution
|
||||
width,
|
||||
(float)m_config.nozzle_diameter.get_at(m_objects.front()->config().support_filament-1),
|
||||
(float)m_config.nozzle_diameter.get_at(physical_extruder),
|
||||
(float)this->skirt_first_layer_height());
|
||||
}
|
||||
|
||||
@@ -2243,6 +2295,17 @@ std::string Print::export_gcode(const std::string& path_template, GCodeProcessor
|
||||
//BBS: compute plate offset for gcode-generator
|
||||
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
|
||||
@@ -2333,7 +2396,9 @@ void Print::_make_skirt()
|
||||
extruders_e_per_mm.reserve(set_extruders.size());
|
||||
for (auto &extruder_id : set_extruders) {
|
||||
extruders.push_back(extruder_id);
|
||||
extruders_e_per_mm.push_back(Extruder((unsigned int)extruder_id, &m_config, m_config.single_extruder_multi_material).e_per_mm(mm3_per_mm));
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2733,8 +2798,11 @@ void Print::_make_wipe_tower()
|
||||
// wipe_tower.set_zhop();
|
||||
|
||||
// Set the extruder & material properties at the wipe tower object.
|
||||
for (size_t i = 0; i < number_of_extruders; ++i)
|
||||
wipe_tower.set_extruder(i, m_config);
|
||||
// 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);
|
||||
}
|
||||
|
||||
// BBS: remove priming logic
|
||||
// m_wipe_tower_data.priming = Slic3r::make_unique<std::vector<WipeTower::ToolChangeResult>>(
|
||||
@@ -2829,8 +2897,11 @@ void Print::_make_wipe_tower()
|
||||
// wipe_tower.set_zhop();
|
||||
|
||||
// Set the extruder & material properties at the wipe tower object.
|
||||
for (size_t i = 0; i < number_of_extruders; ++i)
|
||||
wipe_tower.set_extruder(i, m_config);
|
||||
// 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);
|
||||
}
|
||||
|
||||
m_wipe_tower_data.priming = Slic3r::make_unique<std::vector<WipeTower::ToolChangeResult>>(
|
||||
wipe_tower.prime((float)this->skirt_first_layer_height(), m_wipe_tower_data.tool_ordering.all_extruders(), false));
|
||||
@@ -2970,6 +3041,8 @@ 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);
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
#include <functional>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "calib.hpp"
|
||||
|
||||
@@ -887,6 +888,24 @@ public:
|
||||
|
||||
std::vector<unsigned int> object_extruders() const;
|
||||
std::vector<unsigned int> support_material_extruders() const;
|
||||
|
||||
// SM Orca: 设置耗材-挤出机映射
|
||||
void set_filament_extruder_map(const std::unordered_map<int, int>& map) { m_filament_extruder_map = map; }
|
||||
// SM Orca: 获取耗材-挤出机映射表
|
||||
const std::unordered_map<int, int>& get_filament_extruder_map() const { return m_filament_extruder_map; }
|
||||
// SM Orca: 获取物理挤出机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;
|
||||
// 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_identity]");
|
||||
return physical_extruder_id;
|
||||
}
|
||||
// SM Orca: Initialize filament-to-physical-extruder mapping table
|
||||
void initialize_filament_extruder_map();
|
||||
std::vector<unsigned int> extruders(bool conside_custom_gcode = false) const;
|
||||
double max_allowed_layer_height() const;
|
||||
bool has_support_material() const;
|
||||
@@ -1066,6 +1085,9 @@ private:
|
||||
//SoftFever: calibration
|
||||
Calib_Params m_calib_params;
|
||||
|
||||
// SM Orca: 耗材到物理挤出机的映射表
|
||||
std::unordered_map<int, int> m_filament_extruder_map;
|
||||
|
||||
// To allow GCode to set the Print's GCodeExport step status.
|
||||
friend class GCode;
|
||||
// Allow PrintObject to access m_mutex and m_cancel_callback.
|
||||
|
||||
@@ -216,13 +216,56 @@ 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,
|
||||
const ConfigOption* filament_overrides,
|
||||
const ConfigOption* extruder_defaults,
|
||||
const std::unordered_map<int, int>& filament_extruder_map)
|
||||
{
|
||||
if (!target->is_vector() || !extruder_defaults->is_vector())
|
||||
return;
|
||||
|
||||
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;
|
||||
|
||||
size_t num_filaments = target_vec->size();
|
||||
|
||||
for (size_t filament_idx = 0; filament_idx < num_filaments; ++filament_idx) {
|
||||
// Check if this filament has an override
|
||||
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 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()) {
|
||||
target_vec->set_at(extruder_vec, filament_idx, physical_extruder_idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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,
|
||||
DynamicPrintConfig &filament_overrides,
|
||||
int plate_index)
|
||||
int plate_index,
|
||||
const std::unordered_map<int, int> &filament_extruder_map)
|
||||
{
|
||||
const std::vector<std::string> &extruder_retract_keys = print_config_def.extruder_retract_keys();
|
||||
const std::string filament_prefix = "filament_";
|
||||
@@ -249,6 +292,13 @@ static t_config_option_keys print_config_diffs(
|
||||
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);
|
||||
@@ -261,6 +311,19 @@ static t_config_option_keys print_config_diffs(
|
||||
} else
|
||||
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 if (*opt_new != *opt_old) {
|
||||
//BBS: add plate_index logic for wipe_tower_x/wipe_tower_y
|
||||
if (!opt_key.compare("wipe_tower_x") || !opt_key.compare("wipe_tower_y")) {
|
||||
@@ -1131,7 +1194,8 @@ 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
|
||||
t_config_option_keys print_diff = print_config_diffs(m_config, new_full_config, filament_overrides, this->m_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);
|
||||
|
||||
Reference in New Issue
Block a user