mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-07-23 10:52:15 +00:00
revert filament&extruder
This commit is contained in:
@@ -10,7 +10,6 @@
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include "libslic3r.h"
|
||||
#include "clonable_ptr.hpp"
|
||||
@@ -40,12 +39,6 @@ namespace Slic3r {
|
||||
inline bool operator==(const FloatOrPercent& l, const FloatOrPercent& r) throw() { return l.value == r.value && l.percent == r.percent; }
|
||||
inline bool operator!=(const FloatOrPercent& l, const FloatOrPercent& r) throw() { return !(l == r); }
|
||||
inline bool operator< (const FloatOrPercent& l, const FloatOrPercent& r) throw() { return l.value < r.value || (l.value == r.value && int(l.percent) < int(r.percent)); }
|
||||
inline std::ostream& operator<<(std::ostream& os, const FloatOrPercent& v) {
|
||||
os << v.value;
|
||||
if (v.percent)
|
||||
os << "%";
|
||||
return os;
|
||||
}
|
||||
}
|
||||
|
||||
namespace std {
|
||||
@@ -351,9 +344,6 @@ 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.
|
||||
@@ -429,69 +419,18 @@ public:
|
||||
T v = this->values.front();
|
||||
this->values.resize(i + 1, v);
|
||||
}
|
||||
|
||||
if (rhs->type() == this->type()) {
|
||||
// Assign the first value of the rhs vector.
|
||||
auto other = static_cast<const ConfigOptionVector<T>*>(rhs);
|
||||
if (other->values.empty())
|
||||
throw ConfigurationError("ConfigOptionVector::set_at(): Assigning from an empty vector");
|
||||
|
||||
// Log before assignment
|
||||
std::stringstream before_ss;
|
||||
before_ss << "[";
|
||||
for (size_t k = 0; k < this->values.size(); ++k) {
|
||||
if (k > 0) before_ss << ", ";
|
||||
before_ss << this->values[k];
|
||||
}
|
||||
before_ss << "]";
|
||||
|
||||
// Log other vector
|
||||
std::stringstream other_ss;
|
||||
other_ss << "[";
|
||||
for (size_t k = 0; k < other->values.size(); ++k) {
|
||||
if (k > 0) other_ss << ", ";
|
||||
other_ss << other->values[k];
|
||||
}
|
||||
other_ss << "]";
|
||||
|
||||
this->values[i] = other->get_at(j);
|
||||
|
||||
// Log after assignment
|
||||
std::stringstream after_ss;
|
||||
after_ss << "[";
|
||||
for (size_t k = 0; k < this->values.size(); ++k) {
|
||||
if (k > 0) after_ss << ", ";
|
||||
after_ss << this->values[k];
|
||||
}
|
||||
after_ss << "]";
|
||||
|
||||
|
||||
} else if (rhs->type() == this->scalar_type()) {
|
||||
} else if (rhs->type() == this->scalar_type())
|
||||
this->values[i] = static_cast<const ConfigOptionSingle<T>*>(rhs)->value;
|
||||
} else
|
||||
else
|
||||
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,14 +6,13 @@ namespace Slic3r {
|
||||
double Extruder::m_share_E = 0.;
|
||||
double Extruder::m_share_retracted = 0.;
|
||||
|
||||
Extruder::Extruder(unsigned int id, unsigned int physical_extruder_id, GCodeConfig *config, bool share_extruder) :
|
||||
Extruder::Extruder(unsigned int 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();
|
||||
@@ -158,25 +157,24 @@ 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_physical_extruder_id) * 0.01));
|
||||
return std::min(1., std::max(0., m_config->retract_before_wipe.get_at(m_id) * 0.01));
|
||||
}
|
||||
|
||||
double Extruder::retraction_length() const
|
||||
{
|
||||
return m_config->retraction_length.get_at(m_physical_extruder_id);
|
||||
return m_config->retraction_length.get_at(m_id);
|
||||
}
|
||||
|
||||
double Extruder::retract_lift() const
|
||||
{
|
||||
return m_config->z_hop.get_at(m_physical_extruder_id);
|
||||
return m_config->z_hop.get_at(m_id);
|
||||
}
|
||||
|
||||
int Extruder::retract_speed() const
|
||||
{
|
||||
return int(floor(m_config->retraction_speed.get_at(m_physical_extruder_id)+0.5));
|
||||
return int(floor(m_config->retraction_speed.get_at(m_id)+0.5));
|
||||
}
|
||||
|
||||
bool Extruder::use_firmware_retraction() const
|
||||
@@ -186,28 +184,28 @@ bool Extruder::use_firmware_retraction() const
|
||||
|
||||
int Extruder::deretract_speed() const
|
||||
{
|
||||
int speed = int(floor(m_config->deretraction_speed.get_at(m_physical_extruder_id)+0.5));
|
||||
int speed = int(floor(m_config->deretraction_speed.get_at(m_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_physical_extruder_id);
|
||||
return m_config->retract_restart_extra.get_at(m_id);
|
||||
}
|
||||
|
||||
double Extruder::retract_length_toolchange() const
|
||||
{
|
||||
return m_config->retract_length_toolchange.get_at(m_physical_extruder_id);
|
||||
return m_config->retract_length_toolchange.get_at(m_id);
|
||||
}
|
||||
|
||||
double Extruder::retract_restart_extra_toolchange() const
|
||||
{
|
||||
return m_config->retract_restart_extra_toolchange.get_at(m_physical_extruder_id);
|
||||
return m_config->retract_restart_extra_toolchange.get_at(m_id);
|
||||
}
|
||||
|
||||
double Extruder::travel_slope() const
|
||||
{
|
||||
return m_config->travel_slope.get_at(m_physical_extruder_id) * PI / 180;
|
||||
return m_config->travel_slope.get_at(m_id) * PI / 180;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,8 +11,7 @@ class GCodeConfig;
|
||||
class Extruder
|
||||
{
|
||||
public:
|
||||
// SM Orca: 添加 physical_extruder_id 参数用于支持耗材-挤出机映射
|
||||
Extruder(unsigned int id, unsigned int physical_extruder_id, GCodeConfig *config, bool share_extruder);
|
||||
Extruder(unsigned int id, GCodeConfig *config, bool share_extruder);
|
||||
virtual ~Extruder() {}
|
||||
|
||||
void reset() {
|
||||
@@ -29,8 +28,6 @@ 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);
|
||||
@@ -78,14 +75,12 @@ public:
|
||||
|
||||
private:
|
||||
// Private constructor to create a key for a search in std::set.
|
||||
Extruder(unsigned int id) : m_id(id), m_physical_extruder_id(id) {}
|
||||
Extruder(unsigned int id) : m_id(id) {}
|
||||
|
||||
// Reference to GCodeWriter instance owned by GCodeWriter.
|
||||
GCodeConfig *m_config;
|
||||
// Print-wide global ID of this extruder (filament index).
|
||||
// Print-wide global ID of this extruder.
|
||||
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,73 +213,42 @@ 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();
|
||||
|
||||
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(physical_extruder)),
|
||||
float(object->print()->config().nozzle_diameter.get_at(object->config().support_filament-1)),
|
||||
(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
|
||||
// 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();
|
||||
|
||||
float dmr = float(object->print()->config().nozzle_diameter.get_at(physical_extruder));
|
||||
float dmr = float(object->print()->config().nozzle_diameter.get_at(object->config().support_filament - 1));
|
||||
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();
|
||||
|
||||
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(physical_extruder)),
|
||||
float(print_config.nozzle_diameter.get_at(object->config().support_filament-1)),
|
||||
(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();
|
||||
|
||||
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(physical_extruder)),
|
||||
float(object->print()->config().nozzle_diameter.get_at(object->config().support_interface_filament-1)),
|
||||
(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(GCode& gcodegen, const WipeTower::ToolChangeResult& tcr, const Vec2f& translation, float angle) const;
|
||||
std::string post_process_wipe_tower_moves(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,13 +197,6 @@ 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);
|
||||
if (m_cooling_buffer) m_cooling_buffer->set_filament_extruder_map(map);
|
||||
}
|
||||
|
||||
// Exported for the helper classes (OozePrevention, Wipe) and for the Perl binding for unit tests.
|
||||
const Vec2d& origin() const { return m_origin; }
|
||||
void set_origin(const Vec2d &pointf);
|
||||
|
||||
@@ -482,11 +482,8 @@ static inline float get_default_perimeter_spacing(const PrintObject &print_objec
|
||||
std::vector<unsigned int> printing_extruders = print_object.object_extruders();
|
||||
assert(!printing_extruders.empty());
|
||||
float avg_extruder = 0;
|
||||
for(unsigned int extruder_id : printing_extruders) {
|
||||
// SM Orca: nozzle_diameter是物理挤出机参数,使用physical_extruder_id访问
|
||||
int physical_extruder_id = print_object.print()->get_physical_extruder(extruder_id);
|
||||
avg_extruder += float(scale_(print_object.print()->config().nozzle_diameter.get_at(physical_extruder_id)));
|
||||
}
|
||||
for(unsigned int extruder_id : printing_extruders)
|
||||
avg_extruder += float(scale_(print_object.print()->config().nozzle_diameter.get_at(extruder_id)));
|
||||
avg_extruder /= printing_extruders.size();
|
||||
return avg_extruder;
|
||||
}
|
||||
|
||||
@@ -340,14 +340,12 @@ std::vector<PerExtruderAdjustments> CoolingBuffer::parse_layer_gcode(const std::
|
||||
for (size_t i = 0; i < m_extruder_ids.size(); ++ i) {
|
||||
PerExtruderAdjustments &adj = per_extruder_adjustments[i];
|
||||
unsigned int extruder_id = m_extruder_ids[i];
|
||||
// SM Orca: 冷却参数都是物理挤出机参数(无耗材覆盖),使用physical_extruder_id访问
|
||||
int physical_extruder_id = get_physical_extruder(extruder_id);
|
||||
adj.extruder_id = extruder_id;
|
||||
adj.cooling_slow_down_enabled = m_config.slow_down_for_layer_cooling.get_at(physical_extruder_id);
|
||||
adj.slow_down_layer_time = float(m_config.slow_down_layer_time.get_at(physical_extruder_id));
|
||||
adj.slow_down_min_speed = float(m_config.slow_down_min_speed.get_at(physical_extruder_id));
|
||||
adj.cooling_slow_down_enabled = m_config.slow_down_for_layer_cooling.get_at(extruder_id);
|
||||
adj.slow_down_layer_time = float(m_config.slow_down_layer_time.get_at(extruder_id));
|
||||
adj.slow_down_min_speed = float(m_config.slow_down_min_speed.get_at(extruder_id));
|
||||
// ORCA: To enable dont slow down external perimeters feature per filament (extruder)
|
||||
adj.dont_slow_down_outer_wall = m_config.dont_slow_down_outer_wall.get_at(physical_extruder_id);
|
||||
adj.dont_slow_down_outer_wall = m_config.dont_slow_down_outer_wall.get_at(extruder_id);
|
||||
map_extruder_to_per_extruder_adjustment[extruder_id] = i;
|
||||
}
|
||||
|
||||
@@ -733,8 +731,7 @@ std::string CoolingBuffer::apply_layer_cooldown(
|
||||
&supp_interface_fan_control, &supp_interface_fan_speed,
|
||||
&ironing_fan_control, &ironing_fan_speed
|
||||
](bool immediately_apply) {
|
||||
// SM Orca: 风扇参数都是物理挤出机参数(无耗材覆盖),使用physical_extruder_id访问
|
||||
#define EXTRUDER_CONFIG(OPT) m_config.OPT.get_at(get_physical_extruder(m_current_extruder))
|
||||
#define EXTRUDER_CONFIG(OPT) m_config.OPT.get_at(m_current_extruder)
|
||||
float fan_min_speed = EXTRUDER_CONFIG(fan_min_speed);
|
||||
float fan_speed_new = EXTRUDER_CONFIG(reduce_fan_stop_start_freq) ? fan_min_speed : 0;
|
||||
//BBS
|
||||
|
||||
@@ -27,13 +27,6 @@ public:
|
||||
void reset(const Vec3d &position);
|
||||
void set_current_extruder(unsigned int extruder_id) { m_current_extruder = extruder_id; }
|
||||
std::string process_layer(std::string &&gcode, size_t layer_id, bool flush);
|
||||
// SM Orca: Set filament to physical extruder mapping for correct parameter access
|
||||
void set_filament_extruder_map(const std::unordered_map<int, int>& map) { m_filament_extruder_map = map; }
|
||||
// SM Orca: Get physical extruder ID from filament ID
|
||||
int get_physical_extruder(int filament_idx) const {
|
||||
auto it = m_filament_extruder_map.find(filament_idx);
|
||||
return (it != m_filament_extruder_map.end()) ? it->second : filament_idx;
|
||||
}
|
||||
|
||||
private:
|
||||
CoolingBuffer& operator=(const CoolingBuffer&) = delete;
|
||||
@@ -62,8 +55,6 @@ private:
|
||||
// the PrintConfig slice of FullPrintConfig is constant, thus no thread synchronization is required.
|
||||
const PrintConfig &m_config;
|
||||
unsigned int m_current_extruder;
|
||||
// SM Orca: Filament to physical extruder mapping for correct parameter access
|
||||
std::unordered_map<int, int> m_filament_extruder_map;
|
||||
//BBS: current fan speed
|
||||
int m_current_fan_speed;
|
||||
};
|
||||
|
||||
@@ -94,6 +94,7 @@ const std::vector<std::string> GCodeProcessor::Reserved_Tags_compatible = {
|
||||
" PA_CHANGE:"
|
||||
};
|
||||
|
||||
|
||||
const std::string GCodeProcessor::Flush_Start_Tag = " FLUSH_START";
|
||||
const std::string GCodeProcessor::Flush_End_Tag = " FLUSH_END";
|
||||
|
||||
@@ -396,6 +397,7 @@ void GCodeProcessor::TimeProcessor::reset()
|
||||
filament_unload_times = 0.0f;
|
||||
machine_tool_change_time = 0.0f;
|
||||
|
||||
|
||||
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
|
||||
machines[i].reset();
|
||||
}
|
||||
@@ -455,6 +457,7 @@ void GCodeProcessor::UsedFilaments::process_color_change_cache()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GCodeProcessor::UsedFilaments::process_total_volume_cache(GCodeProcessor* processor)
|
||||
{
|
||||
size_t active_extruder_id = processor->m_extruder_id;
|
||||
@@ -523,17 +526,9 @@ void GCodeProcessor::UsedFilaments::process_role_cache(GCodeProcessor* processor
|
||||
if (role_cache != 0.0f) {
|
||||
std::pair<double, double> filament = { 0.0f, 0.0f };
|
||||
|
||||
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);
|
||||
double s = PI * sqr(0.5 * processor->m_result.filament_diameters[processor->m_extruder_id]);
|
||||
filament.first = role_cache / s * 0.001;
|
||||
filament.second = role_cache * density * 0.001;
|
||||
filament.second = role_cache * processor->m_result.filament_densities[processor->m_extruder_id] * 0.001;
|
||||
|
||||
ExtrusionRole active_role = processor->m_extrusion_role;
|
||||
if (filaments_per_role.find(active_role) != filaments_per_role.end()) {
|
||||
@@ -561,20 +556,6 @@ void GCodeProcessorResult::reset() {
|
||||
//BBS: add mutex for protection of gcode result
|
||||
lock();
|
||||
|
||||
size_t saved_count = extruders_count;
|
||||
|
||||
if (saved_count == 0 || saved_count > 256) {
|
||||
// 尝试从已有数组大小推断(优先使用filament_diameters的大小)
|
||||
if (!filament_diameters.empty() && filament_diameters.size() <= 256) {
|
||||
saved_count = filament_diameters.size();
|
||||
<< saved_count;
|
||||
} else {
|
||||
// 对于只有少量耗材的用户,稍微多分配一些内存影响很小
|
||||
saved_count = 16;
|
||||
<< saved_count << " (was " << extruders_count << ", array size was " << filament_diameters.size() << ")";
|
||||
}
|
||||
}
|
||||
|
||||
moves = std::vector<GCodeProcessorResult::MoveVertex>();
|
||||
printable_area = Pointfs();
|
||||
//BBS: add bed exclude area
|
||||
@@ -586,19 +567,10 @@ void GCodeProcessorResult::reset() {
|
||||
timelapse_warning_code = 0;
|
||||
printable_height = 0.0f;
|
||||
settings_ids.reset();
|
||||
|
||||
extruders_count = saved_count;
|
||||
extruders_count = 0;
|
||||
extruder_colors = std::vector<std::string>();
|
||||
|
||||
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);
|
||||
|
||||
<< " (original extruders_count=" << (saved_count == extruders_count ? "preserved" : "inferred")
|
||||
<< ", this=" << this << ")";
|
||||
|
||||
filament_diameters = std::vector<float>(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DIAMETER);
|
||||
filament_densities = std::vector<float>(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DENSITY);
|
||||
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;
|
||||
@@ -611,18 +583,6 @@ void GCodeProcessorResult::reset() {
|
||||
//BBS: add mutex for protection of gcode result
|
||||
lock();
|
||||
|
||||
size_t saved_count = extruders_count;
|
||||
|
||||
if (saved_count == 0 || saved_count > 256) {
|
||||
// 尝试从已有数组大小推断(优先使用filament_diameters的大小)
|
||||
if (!filament_diameters.empty() && filament_diameters.size() <= 256) {
|
||||
saved_count = filament_diameters.size();
|
||||
} else {
|
||||
// 对于只有少量耗材的用户,稍微多分配一些内存影响很小
|
||||
saved_count = 16;
|
||||
}
|
||||
}
|
||||
|
||||
moves.clear();
|
||||
lines_ends.clear();
|
||||
printable_area = Pointfs();
|
||||
@@ -636,17 +596,13 @@ 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>();
|
||||
|
||||
extruders_count = saved_count;
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
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);
|
||||
@@ -763,40 +719,6 @@ 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));
|
||||
|
||||
size_t physical_extruder_count = config.extruder_offset.values.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);
|
||||
@@ -809,94 +731,20 @@ 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;
|
||||
|
||||
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) {
|
||||
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) << ")";
|
||||
// 使用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_offsets[i] = to_3d(config.extruder_offset.get_at(i).cast<float>().eval(), 0.f);
|
||||
m_extruder_colors[i] = static_cast<unsigned char>(i);
|
||||
|
||||
// 温度是挤出机属性,使用 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;
|
||||
}
|
||||
|
||||
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));
|
||||
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];
|
||||
}
|
||||
|
||||
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";
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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³";
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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";
|
||||
}
|
||||
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));
|
||||
}
|
||||
|
||||
if (m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware || m_flavor == gcfKlipper || m_flavor == gcfRepRapFirmware) {
|
||||
@@ -1010,35 +858,24 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
||||
|
||||
const ConfigOptionFloats* filament_diameters = config.option<ConfigOptionFloats>("filament_diameter");
|
||||
if (filament_diameters != nullptr) {
|
||||
size_t config_size = filament_diameters->values.size();
|
||||
|
||||
if (m_result.filament_diameters.size() < m_result.extruders_count) {
|
||||
m_result.filament_diameters.resize(m_result.extruders_count, DEFAULT_FILAMENT_DIAMETER);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < config_size && i < m_result.extruders_count; ++i) {
|
||||
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) {
|
||||
m_result.filament_diameters[i] = static_cast<float>(filament_diameters->values[i]);
|
||||
}
|
||||
|
||||
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";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_result.filament_diameters.size() < m_result.extruders_count) {
|
||||
m_result.filament_diameters.resize(m_result.extruders_count, DEFAULT_FILAMENT_DIAMETER);
|
||||
for (size_t i = m_result.filament_diameters.size(); i < m_result.extruders_count; ++i) {
|
||||
m_result.filament_diameters.emplace_back(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<int>(filament_HRC->values[i]); }
|
||||
for (size_t i = 0; i < filament_HRC->values.size(); ++i) { m_result.required_nozzle_HRC[i] = static_cast<float>(filament_HRC->values[i]); }
|
||||
}
|
||||
|
||||
if (m_result.required_nozzle_HRC.size() < m_result.extruders_count) {
|
||||
@@ -1048,75 +885,43 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
||||
|
||||
const ConfigOptionFloats* filament_densities = config.option<ConfigOptionFloats>("filament_density");
|
||||
if (filament_densities != nullptr) {
|
||||
size_t config_size = filament_densities->values.size();
|
||||
|
||||
if (m_result.filament_densities.size() < m_result.extruders_count) {
|
||||
m_result.filament_densities.resize(m_result.extruders_count, DEFAULT_FILAMENT_DENSITY);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < config_size && i < m_result.extruders_count; ++i) {
|
||||
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) {
|
||||
m_result.filament_densities[i] = static_cast<float>(filament_densities->values[i]);
|
||||
}
|
||||
|
||||
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³";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_result.filament_densities.size() < m_result.extruders_count) {
|
||||
m_result.filament_densities.resize(m_result.extruders_count, DEFAULT_FILAMENT_DENSITY);
|
||||
for (size_t i = m_result.filament_densities.size(); i < m_result.extruders_count; ++i) {
|
||||
m_result.filament_densities.emplace_back(DEFAULT_FILAMENT_DENSITY);
|
||||
}
|
||||
}
|
||||
|
||||
//BBS
|
||||
const ConfigOptionFloats* filament_costs = config.option<ConfigOptionFloats>("filament_cost");
|
||||
if (filament_costs != nullptr) {
|
||||
size_t config_size = filament_costs->values.size();
|
||||
|
||||
if (m_result.filament_costs.size() < m_result.extruders_count) {
|
||||
m_result.filament_costs.resize(m_result.extruders_count, DEFAULT_FILAMENT_COST);
|
||||
}
|
||||
|
||||
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]);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
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]);
|
||||
}
|
||||
|
||||
if (m_result.filament_costs.size() < m_result.extruders_count) {
|
||||
m_result.filament_costs.resize(m_result.extruders_count, 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);
|
||||
}
|
||||
|
||||
//BBS
|
||||
const ConfigOptionInts* filament_vitrification_temperature = config.option<ConfigOptionInts>("temperature_vitrification");
|
||||
if (filament_vitrification_temperature != nullptr) {
|
||||
size_t config_size = filament_vitrification_temperature->values.size();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < config_size && i < m_result.extruders_count; ++i) {
|
||||
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) {
|
||||
m_result.filament_vitrification_temperature[i] = static_cast<int>(filament_vitrification_temperature->values[i]);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1132,32 +937,17 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
||||
}
|
||||
}
|
||||
else {
|
||||
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) {
|
||||
m_extruder_offsets.resize(extruder_offset->values.size());
|
||||
for (size_t i = 0; i < extruder_offset->values.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) {
|
||||
size_t physical_count = m_extruder_offsets.size();
|
||||
for (size_t i = m_extruder_offsets.size(); i < m_result.extruders_count; ++i) {
|
||||
int physical_extruder = get_physical_extruder(i);
|
||||
// 如果映射的物理挤出机索引在有效范围内,复用它的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)";
|
||||
}
|
||||
m_extruder_offsets.emplace_back(DEFAULT_EXTRUDER_OFFSET);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1201,6 +991,7 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
||||
if (machine_tool_change_time != nullptr)
|
||||
m_time_processor.machine_tool_change_time = static_cast<float>(machine_tool_change_time->value);
|
||||
|
||||
|
||||
if (m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware || m_flavor == gcfKlipper) {
|
||||
const ConfigOptionFloats* machine_max_acceleration_x = config.option<ConfigOptionFloats>("machine_max_acceleration_x");
|
||||
if (machine_max_acceleration_x != nullptr)
|
||||
@@ -1262,6 +1053,7 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
||||
if (machine_max_acceleration_retracting != nullptr)
|
||||
m_time_processor.machine_limits.machine_max_acceleration_retracting.values = machine_max_acceleration_retracting->values;
|
||||
|
||||
|
||||
// Legacy Marlin does not have separate travel acceleration, it uses the 'extruding' value instead.
|
||||
const ConfigOptionFloats* machine_max_acceleration_travel = config.option<ConfigOptionFloats>(m_flavor == gcfMarlinLegacy || m_flavor == gcfKlipper
|
||||
? "machine_max_acceleration_extruding"
|
||||
@@ -1269,6 +1061,7 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
||||
if (machine_max_acceleration_travel != nullptr)
|
||||
m_time_processor.machine_limits.machine_max_acceleration_travel.values = machine_max_acceleration_travel->values;
|
||||
|
||||
|
||||
const ConfigOptionFloats* machine_min_extruding_rate = config.option<ConfigOptionFloats>("machine_min_extruding_rate");
|
||||
if (machine_min_extruding_rate != nullptr)
|
||||
m_time_processor.machine_limits.machine_min_extruding_rate.values = machine_min_extruding_rate->values;
|
||||
@@ -1320,32 +1113,10 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
||||
if (bed_type != nullptr)
|
||||
m_result.bed_type = (BedType)bed_type->value;
|
||||
|
||||
|
||||
const ConfigOptionFloat* z_offset = config.option<ConfigOptionFloat>("z_offset");
|
||||
if (z_offset != nullptr)
|
||||
m_z_offset = z_offset->value;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void GCodeProcessor::enable_stealth_time_estimator(bool enabled)
|
||||
@@ -1785,22 +1556,6 @@ void GCodeProcessor::process_gcode_line(const GCodeReader::GCodeLine& line, bool
|
||||
// update start position
|
||||
m_start_position = m_end_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)
|
||||
{
|
||||
@@ -2880,21 +2635,6 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line, const std::o
|
||||
m_end_position[a] = absolute_position((Axis)a, line);
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -2958,32 +2698,13 @@ 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) {
|
||||
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();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
else if (m_extrusion_role == erBridgeInfill || m_extrusion_role == erInternalBridgeInfill || m_extrusion_role == erNone)
|
||||
// cross section: circle
|
||||
m_width = diameter * std::sqrt(ratio);
|
||||
}
|
||||
m_width = static_cast<float>(m_result.filament_diameters[m_extruder_id]) * std::sqrt(delta_pos[E] / delta_xyz);
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
@@ -3192,6 +2913,7 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line, const std::o
|
||||
// axis reversal
|
||||
std::max(-v_exit, v_entry));
|
||||
|
||||
|
||||
float axis_max_jerk = get_axis_max_jerk(static_cast<PrintEstimatedStatistics::ETimeMode>(i), static_cast<Axis>(a));
|
||||
if (jerk > axis_max_jerk) {
|
||||
v_factor *= axis_max_jerk / jerk;
|
||||
@@ -3364,22 +3086,6 @@ 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);
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -3424,6 +3130,7 @@ void GCodeProcessor::process_G2_G3(const GCodeReader::GCodeLine& line)
|
||||
|
||||
EMoveType type = move_type(delta_pos[E]);
|
||||
|
||||
|
||||
const float delta_xyz = std::sqrt(sqr(arc_length) + sqr(delta_pos[Z]));
|
||||
m_travel_dist = delta_xyz;
|
||||
if (type == EMoveType::Extrude) {
|
||||
@@ -3471,32 +3178,13 @@ 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) {
|
||||
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();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
else if (m_extrusion_role == erBridgeInfill || m_extrusion_role == erInternalBridgeInfill || m_extrusion_role == erNone)
|
||||
//BBS: cross section: circle
|
||||
m_width = diameter * std::sqrt(ratio);
|
||||
}
|
||||
m_width = static_cast<float>(m_result.filament_diameters[m_extruder_id]) * std::sqrt(delta_pos[E] / delta_xyz);
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
@@ -3660,6 +3348,7 @@ void GCodeProcessor::process_G2_G3(const GCodeReader::GCodeLine& line)
|
||||
//BBS: axis reversal
|
||||
std::max(-v_exit, v_entry));
|
||||
|
||||
|
||||
float axis_max_jerk = get_axis_max_jerk(static_cast<PrintEstimatedStatistics::ETimeMode>(i), static_cast<Axis>(a));
|
||||
if (jerk > axis_max_jerk) {
|
||||
v_factor *= axis_max_jerk / jerk;
|
||||
@@ -3885,25 +3574,12 @@ 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];
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -4033,6 +3709,7 @@ void GCodeProcessor::process_M191(const GCodeReader::GCodeLine& line)
|
||||
simulate_st_synchronize(wait_chamber_temp_time);
|
||||
}
|
||||
|
||||
|
||||
void GCodeProcessor::process_M201(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
// see http://reprap.org/wiki/G-code#M201:_Set_max_printing_acceleration
|
||||
@@ -4368,54 +4045,17 @@ void GCodeProcessor::run_post_process()
|
||||
double filament_total_cost = 0.0;
|
||||
|
||||
for (const auto& [id, volume] : m_result.print_statistics.total_volumes_per_extruder) {
|
||||
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;
|
||||
}
|
||||
|
||||
double diameter = m_result.filament_diameters[id];
|
||||
double density = m_result.filament_densities[id];
|
||||
double cost = m_result.filament_costs[id];
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
double cross_section = M_PI * sqr(0.5 * diameter);
|
||||
filament_mm[id] = volume / cross_section;
|
||||
filament_mm[id] = volume / (static_cast<double>(M_PI) * sqr(0.5 * m_result.filament_diameters[id]));
|
||||
filament_cm3[id] = volume * 0.001;
|
||||
filament_g[id] = filament_cm3[id] * density;
|
||||
filament_cost[id] = filament_g[id] * cost * 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_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;
|
||||
|
||||
|
||||
auto time_in_minutes = [](float time_in_seconds) {
|
||||
assert(time_in_seconds >= 0.f);
|
||||
return int((time_in_seconds + 0.5f) / 60.0f);
|
||||
@@ -4543,6 +4183,7 @@ void GCodeProcessor::run_post_process()
|
||||
size_t m_times_cache_id{ 0 };
|
||||
size_t m_out_file_pos{ 0 };
|
||||
|
||||
|
||||
public:
|
||||
ExportLines(EWriteType type,
|
||||
const std::array<TimeMachine, static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count)>& machines)
|
||||
@@ -5112,6 +4753,7 @@ void GCodeProcessor::run_post_process()
|
||||
|
||||
export_lines.flush(out, m_result, out_path);
|
||||
|
||||
|
||||
out.close();
|
||||
in.close();
|
||||
|
||||
@@ -5129,10 +4771,6 @@ void GCodeProcessor::store_move_vertex(EMoveType type, EMovePathType path_type)
|
||||
m_line_id + 1 :
|
||||
((type == EMoveType::Seam) ? m_last_line_id : m_line_id);
|
||||
|
||||
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) {
|
||||
@@ -5141,38 +4779,7 @@ 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()) +
|
||||
extruder_offset;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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_extruder_offsets[m_extruder_id];
|
||||
}
|
||||
|
||||
m_result.moves.push_back({
|
||||
@@ -5182,7 +4789,7 @@ 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
|
||||
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_extruder_offsets[m_extruder_id],
|
||||
static_cast<float>(m_end_position[E] - m_start_position[E]),
|
||||
m_feedrate,
|
||||
m_width,
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <optional>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
@@ -678,8 +677,6 @@ 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
|
||||
@@ -779,16 +776,6 @@ 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;
|
||||
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,20 +668,18 @@ WipeTower::WipeTower(const PrintConfig& config, int plate_idx, Vec3d plate_origi
|
||||
|
||||
|
||||
|
||||
void WipeTower::set_extruder(size_t idx, int physical_extruder, const PrintConfig& config)
|
||||
void WipeTower::set_extruder(size_t idx, 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);
|
||||
// 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);
|
||||
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);
|
||||
|
||||
// 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.
|
||||
@@ -700,19 +698,14 @@ void WipeTower::set_extruder(size_t idx, int physical_extruder, const PrintConfi
|
||||
#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
|
||||
// SM Orca: 喷嘴直径是挤出机属性,使用 physical_extruder
|
||||
float nozzle_diameter = float(config.nozzle_diameter.get_at(physical_extruder));
|
||||
float nozzle_diameter = float(config.nozzle_diameter.get_at(idx));
|
||||
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());
|
||||
|
||||
// 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
|
||||
m_perimeter_width = nozzle_diameter * Width_To_Nozzle_Ratio; // all extruders are now assumed to have the same diameter
|
||||
// BBS: remove useless config
|
||||
#if 0
|
||||
if (m_semm) {
|
||||
@@ -1312,10 +1305,7 @@ WipeTower::ToolChangeResult WipeTower::finish_layer(bool extrude_perimeter, bool
|
||||
}
|
||||
|
||||
// brim chamfer
|
||||
// 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);
|
||||
float spacing = m_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,8 +144,7 @@ public:
|
||||
|
||||
|
||||
// Set the extruder properties.
|
||||
// SM Orca: 添加 physical_extruder 参数,用于支持耗材-挤出机映射
|
||||
void set_extruder(size_t idx, int physical_extruder, const PrintConfig& config);
|
||||
void set_extruder(size_t idx, 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.
|
||||
@@ -270,8 +269,6 @@ 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,9 +45,7 @@ public:
|
||||
|
||||
|
||||
// Set the extruder properties.
|
||||
// SM Orca: 添加 physical_extruder 参数,用于支持耗材-挤出机映射
|
||||
// idx: 耗材索引, physical_extruder: 物理挤出机索引
|
||||
void set_extruder(size_t idx, int physical_extruder, const PrintConfig& config);
|
||||
void set_extruder(size_t idx, 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.
|
||||
@@ -162,8 +160,6 @@ 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:
|
||||
|
||||
@@ -27,10 +27,6 @@ void GCodeWriter::apply_print_config(const PrintConfig &print_config)
|
||||
{
|
||||
this->config.apply(print_config, true);
|
||||
m_single_extruder_multi_material = print_config.single_extruder_multi_material.value;
|
||||
m_physical_extruder_count = print_config.nozzle_diameter.values.size();
|
||||
if (m_physical_extruder_count == 0) {
|
||||
m_physical_extruder_count = 1; // 防止除零,默认为1
|
||||
}
|
||||
bool use_mach_limits = print_config.gcode_flavor.value == gcfMarlinLegacy || print_config.gcode_flavor.value == gcfMarlinFirmware ||
|
||||
print_config.gcode_flavor.value == gcfKlipper || print_config.gcode_flavor.value == gcfRepRapFirmware;
|
||||
m_max_acceleration = std::lrint(use_mach_limits ? print_config.machine_max_acceleration_extruding.values.front() : 0);
|
||||
@@ -49,18 +45,17 @@ void GCodeWriter::apply_print_config(const PrintConfig &print_config)
|
||||
|
||||
void GCodeWriter::set_extruders(std::vector<unsigned int> extruder_ids)
|
||||
{
|
||||
|
||||
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) {
|
||||
int physical_extruder_id = get_physical_extruder(extruder_id);
|
||||
|
||||
m_extruders.emplace_back(Extruder(extruder_id, physical_extruder_id, &this->config, config.single_extruder_multi_material.value));
|
||||
}
|
||||
|
||||
this->multiple_extruders = (*std::max_element(extruder_ids.begin(), extruder_ids.end())) > 0;
|
||||
for (unsigned int extruder_id : extruder_ids)
|
||||
m_extruders.emplace_back(Extruder(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;
|
||||
}
|
||||
|
||||
std::string GCodeWriter::preamble()
|
||||
@@ -404,6 +399,7 @@ std::string GCodeWriter::set_input_shaping(char axis, float damp, float freq) co
|
||||
return gcode.str();
|
||||
}
|
||||
|
||||
|
||||
std::string GCodeWriter::reset_e(bool force)
|
||||
{
|
||||
if (FLAVOR_IS(gcfMach3)
|
||||
@@ -458,9 +454,6 @@ std::string GCodeWriter::toolchange_prefix() const
|
||||
|
||||
std::string GCodeWriter::toolchange(unsigned int extruder_id)
|
||||
{
|
||||
|
||||
int physical_extruder = get_physical_extruder(extruder_id);
|
||||
|
||||
// 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);
|
||||
@@ -476,7 +469,6 @@ std::string GCodeWriter::toolchange(unsigned int extruder_id)
|
||||
gcode << " ; change extruder";
|
||||
gcode << "\n";
|
||||
gcode << this->reset_e(true);
|
||||
} else {
|
||||
}
|
||||
return gcode.str();
|
||||
}
|
||||
@@ -503,7 +495,7 @@ std::string GCodeWriter::travel_to_xy(const Vec2d &point, const std::string &com
|
||||
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
|
||||
@@ -721,7 +713,7 @@ std::string GCodeWriter::extrude_to_xy(const Vec2d &point, double dE, const std:
|
||||
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,7 +4,6 @@
|
||||
#include "libslic3r.h"
|
||||
#include <string>
|
||||
#include <charconv>
|
||||
#include <unordered_map>
|
||||
#include "Extruder.hpp"
|
||||
#include "Point.hpp"
|
||||
#include "PrintConfig.hpp"
|
||||
@@ -120,26 +119,6 @@ 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,避免越界
|
||||
// 例如:4个物理挤出机时,耗材0-7分别映射到0,1,2,3,0,1,2,3
|
||||
int get_physical_extruder(int filament_idx) const {
|
||||
auto it = m_filament_extruder_map.find(filament_idx);
|
||||
int physical_extruder_id;
|
||||
if (it != m_filament_extruder_map.end()) {
|
||||
// 从映射表获取
|
||||
physical_extruder_id = it->second;
|
||||
} else {
|
||||
// 映射表为空或没有该耗材的映射,使用默认模运算映射
|
||||
physical_extruder_id = filament_idx % m_physical_extruder_count;
|
||||
}
|
||||
|
||||
return physical_extruder_id;
|
||||
}
|
||||
|
||||
// Returns whether this flavor supports separate print and travel acceleration.
|
||||
static bool supports_separate_travel_acceleration(GCodeFlavor flavor);
|
||||
private:
|
||||
@@ -191,11 +170,6 @@ 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;
|
||||
// SM Orca: 物理挤出机数量(用于默认模运算映射)
|
||||
size_t m_physical_extruder_count = 1; // 默认为1,防止除零
|
||||
|
||||
enum class Acceleration {
|
||||
Travel,
|
||||
Print
|
||||
|
||||
@@ -293,6 +293,8 @@ 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"
|
||||
@@ -493,56 +495,6 @@ std::vector<unsigned int> Print::extruders(bool conside_custom_gcode) const
|
||||
return extruders;
|
||||
}
|
||||
|
||||
// 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(error) << "Print::initialize_filament_extruder_map: ERROR - No physical extruders configured!";
|
||||
return;
|
||||
}
|
||||
|
||||
// Get all filament indices that will be used
|
||||
std::vector<unsigned int> filament_extruders = this->extruders();
|
||||
|
||||
// IMPORTANT: Always create mappings for ALL configured filaments, not just those used by objects.
|
||||
// This is critical because filament override parameters need to access the mapping for all filaments.
|
||||
// For example, if a user has 8 filaments configured but only uses 4 in their model,
|
||||
// the mapping table must still contain entries for all 8 filaments to correctly
|
||||
// inherit parameters from the corresponding physical extruders.
|
||||
// extruders() returns empty. In this case, use filament_diameter.size() to determine filament count.
|
||||
// This ensures the mapping is created for all configured filaments, not just those used by objects.
|
||||
if (filament_extruders.empty()) {
|
||||
size_t filament_count = m_config.filament_diameter.size();
|
||||
for (size_t i = 0; i < filament_count; ++i) {
|
||||
filament_extruders.push_back((unsigned int)i);
|
||||
}
|
||||
} else {
|
||||
// Even if extruders() returns some values, we need to ensure ALL configured filaments are in the map.
|
||||
// Add any missing filament indices that are configured but not used by objects.
|
||||
size_t configured_filament_count = m_config.filament_diameter.size();
|
||||
for (size_t i = 0; i < configured_filament_count; ++i) {
|
||||
if (std::find(filament_extruders.begin(), filament_extruders.end(), (unsigned int)i) == filament_extruders.end()) {
|
||||
filament_extruders.push_back((unsigned int)i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create mapping: filament_id -> physical_extruder_id
|
||||
// Mapping formula: physical_extruder = filament_id % physical_extruder_count
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int Print::num_object_instances() const
|
||||
{
|
||||
unsigned int instances = 0;
|
||||
@@ -554,10 +506,8 @@ 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()) {
|
||||
int physical_extruder = get_physical_extruder(extruder_id);
|
||||
nozzle_diameter_max = std::max(nozzle_diameter_max, m_config.nozzle_diameter.get_at(physical_extruder));
|
||||
}
|
||||
for (unsigned int extruder_id : this->extruders())
|
||||
nozzle_diameter_max = std::max(nozzle_diameter_max, m_config.nozzle_diameter.get_at(extruder_id));
|
||||
return nozzle_diameter_max;
|
||||
}
|
||||
|
||||
@@ -1235,12 +1185,10 @@ 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
|
||||
int first_physical = get_physical_extruder(extruders.front());
|
||||
double first_nozzle_diam = m_config.nozzle_diameter.get_at(first_physical);
|
||||
double first_nozzle_diam = m_config.nozzle_diameter.get_at(extruders.front());
|
||||
double first_filament_diam = m_config.filament_diameter.get_at(extruders.front());
|
||||
for (const auto& extruder_idx : extruders) {
|
||||
int physical_extruder = get_physical_extruder(extruder_idx);
|
||||
double nozzle_diam = m_config.nozzle_diameter.get_at(physical_extruder);
|
||||
double nozzle_diam = m_config.nozzle_diameter.get_at(extruder_idx);
|
||||
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) {
|
||||
@@ -1346,8 +1294,7 @@ 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) {
|
||||
int physical_extruder = get_physical_extruder(extruder_id);
|
||||
double dmr = m_config.nozzle_diameter.get_at(physical_extruder);
|
||||
double dmr = m_config.nozzle_diameter.get_at(extruder_id);
|
||||
min_nozzle_diameter = std::min(min_nozzle_diameter, dmr);
|
||||
max_nozzle_diameter = std::max(max_nozzle_diameter, dmr);
|
||||
}
|
||||
@@ -1435,10 +1382,9 @@ 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;
|
||||
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(physical_extruder);
|
||||
m_config.nozzle_diameter.get_at(first_layer_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;
|
||||
@@ -1756,13 +1702,11 @@ 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. */
|
||||
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(physical_extruder),
|
||||
(float)m_config.nozzle_diameter.get_at(m_print_regions.front()->config().wall_filament-1),
|
||||
(float)this->skirt_first_layer_height());
|
||||
}
|
||||
|
||||
@@ -1777,13 +1721,11 @@ 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. */
|
||||
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(physical_extruder),
|
||||
(float)m_config.nozzle_diameter.get_at(m_objects.front()->config().support_filament-1),
|
||||
(float)this->skirt_first_layer_height());
|
||||
}
|
||||
|
||||
@@ -1862,6 +1804,7 @@ void PrintObject::copy_layers_overhang_from_shared_object()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// BBS
|
||||
BoundingBox PrintObject::get_first_layer_bbox(float& a, float& layer_height, std::string& name)
|
||||
{
|
||||
@@ -2212,6 +2155,7 @@ void Print::process(long long *time_cost_with_cache, bool use_cache)
|
||||
append(m_first_layer_convex_hull.points, std::move(poly.points));
|
||||
}
|
||||
|
||||
|
||||
if (has_skirt() && ! draft_shield) {
|
||||
// In case that draft shield is NOT active, generate skirt now.
|
||||
// It will be placed around the brim, so brim has to be ready.
|
||||
@@ -2299,42 +2243,11 @@ 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));
|
||||
|
||||
this->initialize_filament_extruder_map();
|
||||
|
||||
for (const auto& pair : m_filament_extruder_map) {
|
||||
}
|
||||
gcode.set_filament_extruder_map(m_filament_extruder_map);
|
||||
gcode.do_export(this, path.c_str(), result, thumbnail_cb);
|
||||
|
||||
//BBS
|
||||
result->conflict_result = m_conflict_result;
|
||||
|
||||
// After G-code export is complete, finalize the output path by replacing placeholders with actual values
|
||||
// This ensures that placeholders like {print_time} are replaced with calculated values
|
||||
// Note: This is needed for direct export (not through BackgroundSlicingProcess) where
|
||||
// finalize_output_path() might not be called automatically
|
||||
std::string final_path = this->print_statistics().finalize_output_path(path);
|
||||
|
||||
// Rename the file from the placeholder path to the finalized path
|
||||
if (final_path != path) {
|
||||
std::error_code ret = rename_file(path, final_path);
|
||||
if (ret) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Failed to rename G-code file from '" << path
|
||||
<< "' to '" << final_path << "': " << ret.message();
|
||||
// If rename fails, return the original path
|
||||
return path;
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(info) << "Renamed G-code file from '" << path
|
||||
<< "' to '" << final_path << "'";
|
||||
// Update result filename to reflect the new path
|
||||
if (result) {
|
||||
result->filename = final_path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return final_path;
|
||||
return path.c_str();
|
||||
}
|
||||
|
||||
void Print::_make_skirt()
|
||||
@@ -2420,8 +2333,7 @@ void Print::_make_skirt()
|
||||
extruders_e_per_mm.reserve(set_extruders.size());
|
||||
for (auto &extruder_id : set_extruders) {
|
||||
extruders.push_back(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));
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2821,10 +2733,8 @@ 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) {
|
||||
int physical_extruder = get_physical_extruder(i);
|
||||
wipe_tower.set_extruder(i, physical_extruder, m_config);
|
||||
}
|
||||
for (size_t i = 0; i < number_of_extruders; ++i)
|
||||
wipe_tower.set_extruder(i, m_config);
|
||||
|
||||
// BBS: remove priming logic
|
||||
// m_wipe_tower_data.priming = Slic3r::make_unique<std::vector<WipeTower::ToolChangeResult>>(
|
||||
@@ -2919,10 +2829,8 @@ 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) {
|
||||
int physical_extruder = get_physical_extruder(i);
|
||||
wipe_tower.set_extruder(i, physical_extruder, m_config);
|
||||
}
|
||||
for (size_t i = 0; i < number_of_extruders; ++i)
|
||||
wipe_tower.set_extruder(i, 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));
|
||||
@@ -3012,10 +2920,7 @@ std::string Print::output_filename(const std::string &filename_base) const
|
||||
{
|
||||
// Set the placeholders for the data know first after the G-code export is finished.
|
||||
// These values will be just propagated into the output file name.
|
||||
// Use cached statistics if available (even if not finished) to avoid placeholders like {print_time}
|
||||
const PrintStatistics& stats = this->print_statistics();
|
||||
bool has_valid_stats = stats.total_used_filament > 0 || !stats.estimated_normal_print_time.empty();
|
||||
DynamicConfig config = (this->finished() || has_valid_stats) ? stats.config() : stats.placeholders();
|
||||
DynamicConfig config = this->finished() ? this->print_statistics().config() : this->print_statistics().placeholders();
|
||||
config.set_key_value("num_filaments", new ConfigOptionInt((int)m_config.nozzle_diameter.size()));
|
||||
config.set_key_value("num_extruders", new ConfigOptionInt((int) m_config.nozzle_diameter.size()));
|
||||
config.set_key_value("plate_name", new ConfigOptionString(get_plate_name()));
|
||||
@@ -3065,7 +2970,6 @@ void Print::export_gcode_from_previous_file(const std::string& file, GCodeProces
|
||||
GCodeProcessor::s_IsBBLPrinter = is_BBL_printer();
|
||||
const Vec3d origin = this->get_plate_origin();
|
||||
processor.set_xy_offset(origin(0), origin(1));
|
||||
processor.set_filament_extruder_map(m_filament_extruder_map);
|
||||
//processor.enable_producers(true);
|
||||
processor.process_file(file);
|
||||
|
||||
@@ -3209,6 +3113,7 @@ const std::string PrintStatistics::TotalFilamentCostValueMask = "; total filamen
|
||||
const std::string PrintStatistics::TotalFilamentUsedWipeTower = "total filament used for wipe tower [g]";
|
||||
const std::string PrintStatistics::TotalFilamentUsedWipeTowerValueMask = "; total filament used for wipe tower [g] = %.2lf\n";
|
||||
|
||||
|
||||
/*add json export/import related functions */
|
||||
#define JSON_POLYGON_CONTOUR "contour"
|
||||
#define JSON_POLYGON_HOLES "holes"
|
||||
@@ -3218,6 +3123,7 @@ const std::string PrintStatistics::TotalFilamentUsedWipeTowerValueMask = "; tota
|
||||
#define JSON_OBJECT_NAME "name"
|
||||
#define JSON_IDENTIFY_ID "identify_id"
|
||||
|
||||
|
||||
#define JSON_LAYERS "layers"
|
||||
#define JSON_SUPPORT_LAYERS "support_layers"
|
||||
#define JSON_TREE_SUPPORT_LAYERS "tree_support_layers"
|
||||
@@ -3254,6 +3160,8 @@ const std::string PrintStatistics::TotalFilamentUsedWipeTowerValueMask = "; tota
|
||||
#define JSON_LAYER_REGION_PERIMETERS "perimeters"
|
||||
#define JSON_LAYER_REGION_FILLS "fills"
|
||||
|
||||
|
||||
|
||||
#define JSON_SURF_TYPE "surface_type"
|
||||
#define JSON_SURF_THICKNESS "thickness"
|
||||
#define JSON_SURF_THICKNESS_LAYER "thickness_layers"
|
||||
@@ -3293,6 +3201,7 @@ const std::string PrintStatistics::TotalFilamentUsedWipeTowerValueMask = "; tota
|
||||
#define JSON_EXTRUSION_NO_EXTRUSION "no_extrusion"
|
||||
#define JSON_EXTRUSION_LOOP_ROLE "loop_role"
|
||||
|
||||
|
||||
static void to_json(json& j, const Points& p_s) {
|
||||
for (const Point& p : p_s)
|
||||
{
|
||||
@@ -3356,6 +3265,7 @@ static void to_json(json& j, const ArcSegment& arc_seg) {
|
||||
j[JSON_ARC_CENTER] = std::move(center_point_json);
|
||||
}
|
||||
|
||||
|
||||
static void to_json(json& j, const Polyline& poly_line) {
|
||||
json points_json = json::array(), fittings_json = json::array();
|
||||
points_json = poly_line.points;
|
||||
@@ -3629,6 +3539,7 @@ static void from_json(const json& j, ArcSegment& arc_seg) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static void from_json(const json& j, Polyline& poly_line) {
|
||||
poly_line.points = j[JSON_POINTS];
|
||||
|
||||
@@ -3839,6 +3750,7 @@ static void convert_layer_region_from_json(const json& j, LayerRegion& layer_reg
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void extract_layer(const json& layer_json, Layer& layer) {
|
||||
//slice_polygons
|
||||
int slice_polygons_count = layer_json[JSON_LAYER_SLICED_POLYGONS].size();
|
||||
@@ -4209,6 +4121,7 @@ int Print::export_cached_data(const std::string& directory, bool with_space)
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int Print::load_cached_data(const std::string& directory)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
|
||||
#include <functional>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "calib.hpp"
|
||||
|
||||
@@ -888,34 +887,6 @@ 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(根据耗材索引)
|
||||
// 关键修复:当映射表为空时,使用模运算而不是直接返回耗材ID,避免越界
|
||||
int get_physical_extruder(int filament_idx) const {
|
||||
auto it = m_filament_extruder_map.find(filament_idx);
|
||||
int physical_extruder_id;
|
||||
if (it != m_filament_extruder_map.end()) {
|
||||
// 从映射表获取
|
||||
physical_extruder_id = it->second;
|
||||
} else {
|
||||
// 映射表为空或没有该耗材的映射,使用默认模运算映射
|
||||
size_t physical_count = m_config.nozzle_diameter.values.size();
|
||||
if (physical_count == 0) {
|
||||
// 防止除零,使用安全的默认值
|
||||
physical_extruder_id = 0;
|
||||
|
||||
} else {
|
||||
physical_extruder_id = filament_idx % physical_count;
|
||||
}
|
||||
}
|
||||
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;
|
||||
@@ -1095,9 +1066,6 @@ 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.
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <cfloat>
|
||||
#include <sstream>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
@@ -217,133 +216,13 @@ static bool custom_per_printz_gcodes_tool_changes_differ(const std::vector<Custo
|
||||
return false;
|
||||
}
|
||||
|
||||
// For each filament slot, if no override is provided, inherit from the mapped physical extruder
|
||||
// IMPORTANT: This function creates a NEW target array with filament_count elements
|
||||
static ConfigOption* apply_physical_extruder_defaults(
|
||||
const ConfigOption* filament_overrides,
|
||||
const ConfigOption* extruder_defaults,
|
||||
size_t filament_count,
|
||||
const std::unordered_map<int, int>& filament_extruder_map)
|
||||
{
|
||||
if (!extruder_defaults->is_vector())
|
||||
return nullptr;
|
||||
|
||||
auto* extruder_vec = dynamic_cast<const ConfigOptionVectorBase*>(extruder_defaults);
|
||||
const ConfigOptionVectorBase* override_vec = filament_overrides ?
|
||||
dynamic_cast<const ConfigOptionVectorBase*>(filament_overrides) : nullptr;
|
||||
|
||||
if (!extruder_vec)
|
||||
return nullptr;
|
||||
|
||||
// Clone the extruder defaults to create the target
|
||||
auto* target = extruder_defaults->clone();
|
||||
auto* target_vec = dynamic_cast<ConfigOptionVectorBase*>(target);
|
||||
if (!target_vec) {
|
||||
delete target;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Resize target to filament_count
|
||||
target_vec->resize(filament_count);
|
||||
|
||||
for (size_t filament_idx = 0; filament_idx < filament_count; ++filament_idx) {
|
||||
bool has_override = false;
|
||||
if (override_vec && filament_idx < override_vec->size()) {
|
||||
if (override_vec->nullable()) {
|
||||
// Nullable type: use override only if not nil (checkbox is checked)
|
||||
has_override = !override_vec->is_nil(filament_idx);
|
||||
} else {
|
||||
// Non-nullable type: check if the value differs from the default (printer config)
|
||||
// Only if it's different do we consider it a user override
|
||||
// Get the default value from the mapped physical extruder
|
||||
auto map_it = filament_extruder_map.find(filament_idx);
|
||||
int physical_extruder_idx;
|
||||
if (map_it != filament_extruder_map.end()) {
|
||||
physical_extruder_idx = map_it->second;
|
||||
} else {
|
||||
// Fallback: use modulo to map filament to physical extruder
|
||||
// This handles edge cases where the map is incomplete or filament_idx is out of range
|
||||
size_t physical_extruder_count = extruder_vec->size();
|
||||
if (physical_extruder_count == 0) {
|
||||
// Should not happen, but safety check
|
||||
physical_extruder_idx = 0;
|
||||
} else {
|
||||
physical_extruder_idx = (int)filament_idx % (int)physical_extruder_count;
|
||||
}
|
||||
}
|
||||
|
||||
if (physical_extruder_idx < extruder_vec->size()) {
|
||||
// Try different types: double, int, bool
|
||||
auto* override_dbl = dynamic_cast<const ConfigOptionVector<double>*>(override_vec);
|
||||
auto* extruder_dbl = dynamic_cast<const ConfigOptionVector<double>*>(extruder_vec);
|
||||
if (override_dbl && extruder_dbl) {
|
||||
// Compare with the value from the mapped physical extruder
|
||||
double override_value = override_dbl->get_at(filament_idx);
|
||||
double default_value = extruder_dbl->get_at(physical_extruder_idx);
|
||||
// Use override only if value differs from default
|
||||
has_override = (override_value != default_value);
|
||||
|
||||
} else {
|
||||
// Try int type
|
||||
auto* override_int = dynamic_cast<const ConfigOptionVector<int>*>(override_vec);
|
||||
auto* extruder_int = dynamic_cast<const ConfigOptionVector<int>*>(extruder_vec);
|
||||
if (override_int && extruder_int) {
|
||||
int override_value = override_int->get_at(filament_idx);
|
||||
int default_value = extruder_int->get_at(physical_extruder_idx);
|
||||
has_override = (override_value != default_value);
|
||||
} else {
|
||||
// Try bool type
|
||||
auto* override_bool = dynamic_cast<const ConfigOptionVector<unsigned char>*>(override_vec);
|
||||
auto* extruder_bool = dynamic_cast<const ConfigOptionVector<unsigned char>*>(extruder_vec);
|
||||
if (override_bool && extruder_bool) {
|
||||
unsigned char override_value = override_bool->get_at(filament_idx);
|
||||
unsigned char default_value = extruder_bool->get_at(physical_extruder_idx);
|
||||
has_override = (override_value != default_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!has_override) {
|
||||
// No override: inherit from the mapped physical extruder
|
||||
auto map_it = filament_extruder_map.find(filament_idx);
|
||||
int physical_extruder_idx;
|
||||
if (map_it != filament_extruder_map.end()) {
|
||||
physical_extruder_idx = map_it->second;
|
||||
} else {
|
||||
// Fallback: use modulo to map filament to physical extruder
|
||||
// This handles edge cases where the map is incomplete or filament_idx is out of range
|
||||
size_t physical_extruder_count = extruder_vec->size();
|
||||
if (physical_extruder_count == 0) {
|
||||
// Should not happen, but safety check
|
||||
physical_extruder_idx = 0;
|
||||
} else {
|
||||
physical_extruder_idx = (int)filament_idx % (int)physical_extruder_count;
|
||||
}
|
||||
}
|
||||
|
||||
if (physical_extruder_idx < extruder_vec->size() && filament_idx < target_vec->size()) {
|
||||
target_vec->set_at(extruder_vec, filament_idx, physical_extruder_idx);
|
||||
}
|
||||
} else if (override_vec && filament_idx < override_vec->size()) {
|
||||
// Has override: use the value from filament config
|
||||
target_vec->set_at(override_vec, filament_idx, filament_idx);
|
||||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
// Collect changes to print config, account for overrides of extruder retract values by filament presets.
|
||||
//BBS: add plate index
|
||||
static t_config_option_keys print_config_diffs(
|
||||
const PrintConfig ¤t_config,
|
||||
const DynamicPrintConfig &new_full_config,
|
||||
DynamicPrintConfig &filament_overrides,
|
||||
int plate_index,
|
||||
const std::unordered_map<int, int> &filament_extruder_map)
|
||||
int plate_index)
|
||||
{
|
||||
const std::vector<std::string> &extruder_retract_keys = print_config_def.extruder_retract_keys();
|
||||
const std::string filament_prefix = "filament_";
|
||||
@@ -362,81 +241,25 @@ static t_config_option_keys print_config_diffs(
|
||||
// const ConfigOption *opt_new_filament = std::binary_search(extruder_retract_keys.begin(), extruder_retract_keys.end(), opt_key) ? new_full_config.option(filament_prefix + opt_key) : nullptr;
|
||||
const ConfigOption* opt_new_filament = (iter == extruder_retract_keys.end()) ? nullptr :
|
||||
new_full_config.option(filament_prefix + opt_key);
|
||||
|
||||
bool is_extruder_retract_param = (iter != extruder_retract_keys.end());
|
||||
|
||||
// 1. This is an extruder retract parameter AND
|
||||
// 2. Filament overrides exist AND
|
||||
// 3. Filament-extruder map is not empty (meaning objects are loaded and mapping is initialized)
|
||||
// When user edits printer config directly (without objects loaded or without filament overrides),
|
||||
// we should treat it as a regular config change to ensure UI updates work correctly.
|
||||
bool has_filament_overrides = (opt_new_filament != nullptr && !opt_new_filament->is_nil());
|
||||
bool needs_physical_mapping = is_extruder_retract_param && has_filament_overrides && !filament_extruder_map.empty();
|
||||
|
||||
if (needs_physical_mapping) {
|
||||
|
||||
// This is safe because both opt_old and opt_new should have the same number of physical extruders
|
||||
bool printer_config_changed = (*opt_old != *opt_new);
|
||||
|
||||
auto* override_vec = dynamic_cast<const ConfigOptionVectorBase*>(opt_new_filament);
|
||||
if (override_vec) {
|
||||
BOOST_LOG_TRIVIAL(info) << "print_config_diffs: " << opt_key
|
||||
<< " - filament_override size=" << override_vec->size()
|
||||
<< ", nullable=" << override_vec->nullable();
|
||||
}
|
||||
|
||||
// since we know has_filament_overrides is true at this point
|
||||
if ((opt_key == "long_retractions_when_cut" || opt_key == "retraction_distances_when_cut")
|
||||
&& new_full_config.option<ConfigOptionInt>("enable_long_retraction_when_cut")->value != LongRectrationLevel::EnableFilament)
|
||||
continue;
|
||||
|
||||
// - Check if printer config or filament override changed the effective value
|
||||
// - Only add to print_diff (not filament_overrides) to avoid array size mismatch
|
||||
// The actual filament->extruder mapping is applied later during config usage
|
||||
//
|
||||
// 关键修复:只要打印机配置变化了,就应该添加到 print_diff
|
||||
// 这确保了用户在UI中修改打印机配置时,修改能被正确保存
|
||||
auto opt_copy = opt_new->clone();
|
||||
opt_copy->apply_override(opt_new_filament);
|
||||
if (printer_config_changed || *opt_old != *opt_copy) {
|
||||
print_diff.emplace_back(opt_key);
|
||||
BOOST_LOG_TRIVIAL(info) << "print_config_diffs: " << opt_key
|
||||
<< " - adding to print_diff (printer_changed=" << (printer_config_changed ? "Y" : "N")
|
||||
<< ", effective_changed=" << (*opt_old != *opt_copy ? "Y" : "N") << ")";
|
||||
}
|
||||
delete opt_copy;
|
||||
} else if (opt_new_filament != nullptr && ! opt_new_filament->is_nil()) {
|
||||
if (opt_new_filament != nullptr && ! opt_new_filament->is_nil()) {
|
||||
// An extruder retract override is available at some of the filament presets.
|
||||
bool overriden = opt_new->overriden_by(opt_new_filament);
|
||||
|
||||
bool printer_config_changed = (*opt_old != *opt_new);
|
||||
|
||||
if (overriden || printer_config_changed) {
|
||||
if (overriden || *opt_old != *opt_new) {
|
||||
auto opt_copy = opt_new->clone();
|
||||
if (!((opt_key == "long_retractions_when_cut" || opt_key == "retraction_distances_when_cut")
|
||||
&& new_full_config.option<ConfigOptionInt>("enable_long_retraction_when_cut")->value != LongRectrationLevel::EnableFilament)) // ugly code, remove it later if firmware supports
|
||||
opt_copy->apply_override(opt_new_filament);
|
||||
|
||||
bool changed = *opt_old != *opt_copy;
|
||||
if (changed)
|
||||
print_diff.emplace_back(opt_key);
|
||||
|
||||
// If user directly edited printer config, don't override it with filament values
|
||||
if ((changed || overriden) && !printer_config_changed) {
|
||||
if (changed || overriden) {
|
||||
if ((opt_key == "long_retractions_when_cut" || opt_key == "retraction_distances_when_cut")
|
||||
&& new_full_config.option<ConfigOptionInt>("enable_long_retraction_when_cut")->value != LongRectrationLevel::EnableFilament)
|
||||
continue;
|
||||
// filament_overrides will be applied to the placeholder parser, which layers these parameters over full_print_config.
|
||||
filament_overrides.set_key_value(opt_key, opt_copy);
|
||||
} else if (changed && printer_config_changed) {
|
||||
// Only add to print_diff, not to filament_overrides
|
||||
// This preserves user's printer config edit
|
||||
BOOST_LOG_TRIVIAL(info) << "print_config_diffs: " << opt_key
|
||||
<< " - printer config changed, not adding to filament_overrides to preserve user edit";
|
||||
} else
|
||||
delete opt_copy;
|
||||
} else {
|
||||
delete opt_copy;
|
||||
}
|
||||
}
|
||||
} else if (*opt_new != *opt_old) {
|
||||
//BBS: add plate_index logic for wipe_tower_x/wipe_tower_y
|
||||
@@ -1271,10 +1094,6 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
||||
// BBS
|
||||
int used_filaments = this->extruders(true).size();
|
||||
|
||||
// 此时 m_objects 和 m_config 是稳定的,可以安全地计算映射
|
||||
// 这确保了 print_config_diffs 中的参数继承机制能正常工作
|
||||
this->initialize_filament_extruder_map();
|
||||
|
||||
//new_full_config.normalize_fdm(used_filaments);
|
||||
new_full_config.normalize_fdm_1();
|
||||
t_config_option_keys changed_keys = new_full_config.normalize_fdm_2(objects().size(), used_filaments);
|
||||
@@ -1312,36 +1131,12 @@ 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, m_filament_extruder_map);
|
||||
t_config_option_keys print_diff = print_config_diffs(m_config, new_full_config, filament_overrides, this->m_plate_index);
|
||||
t_config_option_keys full_config_diff = full_print_config_diffs(m_full_print_config, new_full_config, this->m_plate_index);
|
||||
// Collect changes to object and region configs.
|
||||
t_config_option_keys object_diff = m_default_object_config.diff(new_full_config);
|
||||
t_config_option_keys region_diff = m_default_region_config.diff(new_full_config);
|
||||
|
||||
//
|
||||
// 问题根源:
|
||||
// 1. 回抽参数(如retraction_length)既存在于打印机配置,也可能被耗材覆盖
|
||||
// 2. 当耗材-挤出机映射激活时(m_filament_extruder_map不为空),
|
||||
// filament_overrides中的回抽值会覆盖用户对打印机配置的直接修改
|
||||
//
|
||||
// 修复策略:
|
||||
// - 当存在耗材-挤出机映射时(说明已加载项目),移除filament_overrides中的所有回抽参数
|
||||
// - 这样用户的打印机配置修改就不会被耗材覆盖值覆盖
|
||||
// - 保留filament_overrides中其他参数的功能不受影响
|
||||
//
|
||||
// 注意:此修复确保用户对打印机挤出机回抽参数的直接编辑拥有最高优先级
|
||||
const std::vector<std::string> &extruder_retract_keys = print_config_def.extruder_retract_keys();
|
||||
bool has_mapping = !m_filament_extruder_map.empty();
|
||||
if (has_mapping) {
|
||||
// 当有映射时,移除所有回抽参数的耗材覆盖,让打印机配置生效
|
||||
for (const std::string &key : extruder_retract_keys) {
|
||||
if (filament_overrides.erase(key)) {
|
||||
BOOST_LOG_TRIVIAL(info) << "Print::apply - Clearing filament override for '" << key
|
||||
<< "' to allow printer config to take effect (filament-extruder mapping active)";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Do not use the ApplyStatus as we will use the max function when updating apply_status.
|
||||
unsigned int apply_status = APPLY_STATUS_UNCHANGED;
|
||||
auto update_apply_status = [&apply_status](bool invalidated)
|
||||
@@ -1755,10 +1550,6 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
||||
m_full_print_config = std::move(new_full_config);
|
||||
}
|
||||
|
||||
// 在对象同步后,m_objects 可能已经被重建,需要重新计算映射以反映最新状态
|
||||
// 这确保了后续使用映射表时(如 export_gcode)能获得正确的映射关系
|
||||
this->initialize_filament_extruder_map();
|
||||
|
||||
// All regions now have distinct settings.
|
||||
// Check whether applying the new region config defaults we would get different regions,
|
||||
// update regions or create regions from scratch.
|
||||
|
||||
@@ -136,12 +136,12 @@ void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt
|
||||
}
|
||||
case coPercents:{
|
||||
ConfigOptionPercents* vec_new = new ConfigOptionPercents{ boost::any_cast<double>(value) };
|
||||
config.option<ConfigOptionPercents>(opt_key)->set_at(vec_new, opt_index, 0); // SM Orca: Fix - use src_idx=0 for single-element vectors
|
||||
config.option<ConfigOptionPercents>(opt_key)->set_at(vec_new, opt_index, opt_index);
|
||||
break;
|
||||
}
|
||||
case coFloats:{
|
||||
ConfigOptionFloats* vec_new = new ConfigOptionFloats{ boost::any_cast<double>(value) };
|
||||
config.option<ConfigOptionFloats>(opt_key)->set_at(vec_new, opt_index, 0); // SM Orca: Fix - use src_idx=0 for single-element vectors
|
||||
config.option<ConfigOptionFloats>(opt_key)->set_at(vec_new, opt_index, opt_index);
|
||||
break;
|
||||
}
|
||||
case coString:
|
||||
|
||||
@@ -645,10 +645,6 @@ void ConfigOptionsGroup::on_change_OG(const t_config_option_key& opt_id, const b
|
||||
const std::string &opt_key = itOption.first;
|
||||
int opt_index = itOption.second;
|
||||
|
||||
// SM Orca: Debug logging - track parameter changes from UI
|
||||
BOOST_LOG_TRIVIAL(error) << "ConfigOptionsGroup::on_change_OG: opt_id=" << opt_id
|
||||
<< ", opt_key=" << opt_key << ", opt_index=" << opt_index;
|
||||
|
||||
this->change_opt_value(opt_key, value, opt_index == -1 ? 0 : opt_index);
|
||||
}
|
||||
|
||||
@@ -1231,12 +1227,18 @@ void ExtruderOptionsGroup::on_change_OG(const t_config_option_key& opt_id, const
|
||||
|
||||
auto itOption = it->second;
|
||||
const std::string& opt_key = itOption.first;
|
||||
int opt_index = itOption.second;
|
||||
|
||||
// SM Orca: FIX - Only modify the specific extruder's value, not all extruders
|
||||
// The original code iterated through all indices and set them to the same value,
|
||||
// which caused all extruders to have identical values when editing one extruder
|
||||
this->change_opt_value(opt_key, value, opt_index == -1 ? 0 : opt_index);
|
||||
auto opt = m_config->option(opt_key);
|
||||
const ConfigOptionVectorBase* opt_vec = dynamic_cast<const ConfigOptionVectorBase*>(opt);
|
||||
if (opt_vec != nullptr) {
|
||||
for (int opt_index = 0; opt_index < opt_vec->size(); opt_index++) {
|
||||
this->change_opt_value(opt_key, value, opt_index);
|
||||
}
|
||||
}
|
||||
else {
|
||||
int opt_index = itOption.second;
|
||||
this->change_opt_value(opt_key, value, opt_index == -1 ? 0 : opt_index);
|
||||
}
|
||||
}
|
||||
|
||||
OptionsGroup::on_change_OG(opt_id, value);
|
||||
|
||||
@@ -3286,24 +3286,7 @@ void TabFilament::add_filament_overrides_page()
|
||||
else {
|
||||
const std::string printer_opt_key = opt_key.substr(strlen("filament_"));
|
||||
const auto printer_config = m_preset_bundle->printers.get_edited_preset().config;
|
||||
// SM Orca: Map filament slot to physical extruder index for inheritance
|
||||
auto& filament_extruder_map = wxGetApp().app_config->get_filament_extruder_map_ref();
|
||||
// SM Orca: First calculate num_extruders to use modulo for default mapping
|
||||
const ConfigOptionFloats* nozzle_diameter = printer_config.option<ConfigOptionFloats>("nozzle_diameter");
|
||||
int num_extruders = nozzle_diameter ? (int)nozzle_diameter->values.size() : 1;
|
||||
// SM Orca: Use modulo arithmetic for default mapping when no explicit mapping exists
|
||||
int physical_extruder_idx = opt_index % num_extruders; // default: filament N maps to extruder N % num_extruders
|
||||
auto map_it = filament_extruder_map.find(opt_index);
|
||||
if (map_it != filament_extruder_map.end()) {
|
||||
physical_extruder_idx = map_it->second;
|
||||
}
|
||||
// SM Orca: Bounds check to prevent crash from misconfigured map
|
||||
if (physical_extruder_idx < 0 || physical_extruder_idx >= num_extruders) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Invalid physical_extruder_idx " << physical_extruder_idx
|
||||
<< " for filament slot " << opt_index << ", using default";
|
||||
physical_extruder_idx = std::clamp(physical_extruder_idx, 0, num_extruders - 1);
|
||||
}
|
||||
const boost::any printer_config_value = optgroup_sh->get_config_value(printer_config, printer_opt_key, physical_extruder_idx);
|
||||
const boost::any printer_config_value = optgroup_sh->get_config_value(printer_config, printer_opt_key, opt_index);
|
||||
field->update_na_value(printer_config_value);
|
||||
field->set_na_value();
|
||||
}
|
||||
@@ -3318,7 +3301,7 @@ void TabFilament::add_filament_overrides_page()
|
||||
optgroup->append_line(line);
|
||||
};
|
||||
|
||||
const int extruder_idx = (m_presets_choice && m_presets_choice->get_filament_idx() >= 0) ? m_presets_choice->get_filament_idx() : 0; // SM Orca: Get actual filament slot index
|
||||
const int extruder_idx = 0; // #ys_FIXME
|
||||
|
||||
for (const std::string opt_key : { "filament_retraction_length",
|
||||
"filament_z_hop",
|
||||
@@ -3384,7 +3367,7 @@ void TabFilament::update_filament_overrides_page(const DynamicPrintConfig* print
|
||||
// "filament_seam_gap"
|
||||
};
|
||||
|
||||
const int extruder_idx = (m_presets_choice && m_presets_choice->get_filament_idx() >= 0) ? m_presets_choice->get_filament_idx() : 0; // SM Orca: Get actual filament slot index
|
||||
const int extruder_idx = 0; // #ys_FIXME
|
||||
|
||||
const bool have_retract_length = m_config->option("filament_retraction_length")->is_nil() ||
|
||||
m_config->opt_float("filament_retraction_length", extruder_idx) > 0;
|
||||
@@ -3416,26 +3399,7 @@ void TabFilament::update_filament_overrides_page(const DynamicPrintConfig* print
|
||||
} else {
|
||||
if (!is_checked) {
|
||||
const std::string printer_opt_key = opt_key.substr(strlen("filament_"));
|
||||
// SM Orca: Map filament slot to physical extruder index for inheritance
|
||||
auto& filament_extruder_map = wxGetApp().app_config->get_filament_extruder_map_ref();
|
||||
// SM Orca: Determine extruder count first for proper modulo calculation
|
||||
const ConfigOptionFloats* nozzle_diameter = printers_config->option<ConfigOptionFloats>("nozzle_diameter");
|
||||
int num_extruders = nozzle_diameter ? (int)nozzle_diameter->values.size() : 1;
|
||||
int physical_extruder_idx = extruder_idx; // default: filament N uses extruder N
|
||||
auto map_it = filament_extruder_map.find(extruder_idx);
|
||||
if (map_it != filament_extruder_map.end()) {
|
||||
physical_extruder_idx = map_it->second;
|
||||
} else {
|
||||
// SM Orca: Use modulo arithmetic when map entry doesn't exist
|
||||
physical_extruder_idx = extruder_idx % num_extruders;
|
||||
}
|
||||
// SM Orca: Bounds check to prevent crash from misconfigured map
|
||||
if (physical_extruder_idx < 0 || physical_extruder_idx >= num_extruders) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Invalid physical_extruder_idx " << physical_extruder_idx
|
||||
<< " for filament slot " << extruder_idx << ", using default";
|
||||
physical_extruder_idx = std::clamp(physical_extruder_idx, 0, num_extruders - 1);
|
||||
}
|
||||
boost::any printer_config_value = optgroup->get_config_value(*printers_config, printer_opt_key, physical_extruder_idx);
|
||||
boost::any printer_config_value = optgroup->get_config_value(*printers_config, printer_opt_key, extruder_idx);
|
||||
field->update_na_value(printer_config_value);
|
||||
field->set_value(printer_config_value, false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user