mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-07-20 17:32:26 +00:00
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:
@@ -404,3 +404,55 @@ TEST_CASE("EXTRUDER_LIMIT per-extruder clamping and max fallback", "[GCodeWriter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCENARIO("Extruder reads the injected config column", "[GCodeWriter][H2C]") {
|
||||
GIVEN("A writer whose per-variant arrays hold three columns for two filaments") {
|
||||
GCodeWriter writer;
|
||||
// Column layout after a migrating regroup: filament 0 -> column 0, filament 1 ->
|
||||
// columns 1 (its first variant) and 2 (its second variant).
|
||||
writer.config.retraction_length.values = {0.8, 0.5, 1.2};
|
||||
writer.config.z_hop.values = {0.4, 0.6, 0.9};
|
||||
writer.config.retraction_speed.values = {30., 40., 50.};
|
||||
writer.config.filament_flow_ratio.values = {0.98, 1.0, 1.02};
|
||||
// Filament-indexed arrays keep one entry per filament.
|
||||
writer.config.filament_diameter.values = {1.75, 1.75};
|
||||
writer.set_extruders({0, 1});
|
||||
writer.toolchange(1);
|
||||
Extruder *fil = writer.filament();
|
||||
REQUIRE(fil != nullptr);
|
||||
REQUIRE(fil->id() == 1);
|
||||
const double crossection = 1.75 * 1.75 * 0.25 * PI;
|
||||
|
||||
WHEN("no column has been injected") {
|
||||
THEN("the getters read the filament id's column") {
|
||||
REQUIRE(fil->config_index() == 1);
|
||||
REQUIRE_THAT(fil->retraction_length(), Catch::Matchers::WithinAbs(0.5, 1e-9));
|
||||
REQUIRE_THAT(fil->retract_lift(), Catch::Matchers::WithinAbs(0.6, 1e-9));
|
||||
REQUIRE(fil->retract_speed() == 40);
|
||||
REQUIRE_THAT(fil->e_per_mm3(), Catch::Matchers::WithinRel(1.0 / crossection, 1e-9));
|
||||
}
|
||||
}
|
||||
WHEN("the second variant column is injected") {
|
||||
fil->set_config_index(2);
|
||||
THEN("the getters follow the column and the flow cache is rescaled") {
|
||||
REQUIRE(fil->config_index() == 2);
|
||||
REQUIRE_THAT(fil->retraction_length(), Catch::Matchers::WithinAbs(1.2, 1e-9));
|
||||
REQUIRE_THAT(fil->retract_lift(), Catch::Matchers::WithinAbs(0.9, 1e-9));
|
||||
REQUIRE(fil->retract_speed() == 50);
|
||||
REQUIRE_THAT(fil->e_per_mm3(), Catch::Matchers::WithinRel(1.02 / crossection, 1e-9));
|
||||
}
|
||||
THEN("filament-indexed reads keep using the filament id") {
|
||||
REQUIRE_THAT(fil->filament_diameter(), Catch::Matchers::WithinAbs(1.75, 1e-9));
|
||||
}
|
||||
}
|
||||
WHEN("a negative index is injected") {
|
||||
fil->set_config_index(2);
|
||||
fil->set_config_index(-1);
|
||||
THEN("resolution resets to the filament id") {
|
||||
REQUIRE(fil->config_index() == 1);
|
||||
REQUIRE_THAT(fil->retraction_length(), Catch::Matchers::WithinAbs(0.5, 1e-9));
|
||||
REQUIRE_THAT(fil->e_per_mm3(), Catch::Matchers::WithinRel(1.0 / crossection, 1e-9));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user