feat(engine): resolve per-variant config columns for raw filament reads on the export path

When a per-layer nozzle grouping migrates a filament across nozzle
variants, the write-back turns two groups of config arrays from
filament-indexed into column-indexed: the per-variant filament options
(one column per variant a filament uses) and the merged extruder
retract overrides (resized to the column count by apply_override).
Export-path readers that still indexed them with the raw filament id
read a neighbor's column for every filament ordered after a migrating
one: toolchange/standby temperatures (M104/M109), retraction lengths
and feedrates, wipe distance, z-hop types, air-filtration keys, and -
through the Extruder's cached flow term - the extrusion E of every
move.

Now every such read resolves its column through the existing
layer-aware resolver (get_filament_config_index ->
Print::get_filament_config_indx), which returns the raw filament id
whenever no per-layer grouping result is published, so static prints
are byte-inert by construction. The Extruder itself has no layer
knowledge, so it gains an injected config column (set_config_index,
default = filament id) that the generator refreshes at the only two
resolution-changing events - layer change and writer toolchange - and
that re-syncs the cached e_per_mm3 flow term. Old-filament reads
resolve at the current layer, which is safe because the per-layer maps
are gap-filled carry-forward. Whole-array placeholder copies
(toolchange temperature overrides) are rebuilt in filament order,
mirroring the existing per-variant placeholder remap. The resolvers
move to the public section so non-friend helpers (ooze prevention) can
resolve too.

Documented, deliberately unchanged: the wipe tower's per-filament
parameter rows (no layer dimension; tower x per-layer grouping is a
follow-up), travel_slope's physical-extruder read, estimator pre-heat
bookkeeping temps, and index-0 header diagnostics.

Verification: new Extruder column-injection scenario (defaults, column
follow + flow-cache rescale, filament-indexed reads unaffected, reset
semantics) and a migrating write-back case proving the column shift for
filaments ordered after a migrator and the resolver tracking it (11 +
14 assertions); suites green (libslic3r 48998/169, fff_print 655/61);
20/20 pinned-slice byte gate bit-identical (incl. sequential repro x2
deterministic).
This commit is contained in:
SoftFever
2026-07-12 14:30:39 +08:00
parent abbd420f2a
commit 582017235c
9 changed files with 275 additions and 64 deletions

View File

@@ -13,11 +13,20 @@ Extruder::Extruder(unsigned int id, GCodeConfig *config, bool share_extruder) :
{
reset();
m_config_index = int(m_id);
// cache values that are going to be called often
m_e_per_mm3 = this->filament_flow_ratio();
m_e_per_mm3 /= this->filament_crossection();
}
void Extruder::set_config_index(int idx)
{
m_config_index = idx < 0 ? int(m_id) : idx;
// keep the cached flow term reading the same column as the getters
m_e_per_mm3 = this->filament_flow_ratio();
m_e_per_mm3 /= this->filament_crossection();
}
unsigned int Extruder::extruder_id() const
{
assert(m_config);
@@ -162,28 +171,28 @@ double Extruder::filament_cost() const
double Extruder::filament_flow_ratio() const
{
return m_config->filament_flow_ratio.get_at(m_id);
return m_config->filament_flow_ratio.get_at(m_config_index);
}
// Return a "retract_before_wipe" percentage as a factor clamped to <0, 1>
double Extruder::retract_before_wipe() const
{
return std::min(1., std::max(0., m_config->retract_before_wipe.get_at(m_id) * 0.01));
return std::min(1., std::max(0., m_config->retract_before_wipe.get_at(m_config_index) * 0.01));
}
double Extruder::retraction_length() const
{
return m_config->retraction_length.get_at(m_id);
return m_config->retraction_length.get_at(m_config_index);
}
double Extruder::retract_lift() const
{
return m_config->z_hop.get_at(m_id);
return m_config->z_hop.get_at(m_config_index);
}
int Extruder::retract_speed() const
{
return int(floor(m_config->retraction_speed.get_at(m_id)+0.5));
return int(floor(m_config->retraction_speed.get_at(m_config_index)+0.5));
}
bool Extruder::use_firmware_retraction() const
@@ -193,13 +202,13 @@ bool Extruder::use_firmware_retraction() const
int Extruder::deretract_speed() const
{
int speed = int(floor(m_config->deretraction_speed.get_at(m_id)+0.5));
int speed = int(floor(m_config->deretraction_speed.get_at(m_config_index)+0.5));
return (speed > 0) ? speed : this->retract_speed();
}
double Extruder::retract_restart_extra() const
{
return m_config->retract_restart_extra.get_at(m_id);
return m_config->retract_restart_extra.get_at(m_config_index);
}
double Extruder::retract_length_toolchange() const
@@ -214,6 +223,8 @@ double Extruder::retract_restart_extra_toolchange() const
double Extruder::travel_slope() const
{
// Orca: deliberately keyed by the physical extruder, not the filament column — this read
// predates the per-variant merge and switching it would change existing multi-extruder output.
return m_config->travel_slope.get_at(extruder_id()) * PI / 180;
}