mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-08-04 08:42:10 +00:00
feat(engine): write per-variant filament values back for selector regroups
When the per-layer filament selector (enable_filament_dynamic_map) migrates a filament across nozzle variants (e.g. Standard -> High Flow), the config write-back only stored the derived extruder map; every per-variant filament value (retraction, nozzle temperature, flow, flush...) kept the numbers resolved from the pre-slice static mapping. Now both dynamic write-back sites (the by-layer branch and the sequential stitch) branch on the result's dynamic support. Migrating results run a mixed-filament expansion that regathers every filament_options_with_variant key from the pristine per-variant superset, giving a migrating filament one config slot per (extruder type x nozzle volume type) it lands on - filament_self_index, filament_extruder_variant, and all value arrays grow in lockstep - and recompute the retract overrides with per-slot machine indices so a nil slot falls back to its own variant's machine value. Non-migrating dynamic results take the merged three-map write-back so re-applies reproduce from the written maps. Unrouted filaments resolve from the result's own default map, so slot resolution never depends on filament_map round-tripping through the plate config. Print::apply reproduces the identical expansion from the persisted group result (shared dedupe helper, expansion function, and slot indices on both sides): the expanded keys sit in the psWipeTower / psGCodeExport invalidate lists, so without the reproduction every re-apply after a selector slice would diff non-empty and permanently invalidate. cal_non_support_filaments now resolves the extruder per layer from the published result for dynamic groupings. filament_map_2 keeps its apply-time static derivation; nothing on the dynamic path reads it (the per-slot machine indices key the override merge), and per-(extruder x volume-type) machine limits in the g-code processor remain a documented follow-up. Every change is gated behind is_dynamic_group_reorder() or a persisted result with dynamic support; no profile sets the flag, so the static fleet's instruction stream is unchanged (20/20 pinned-slice byte gate identical, incl. the sequential repro sliced twice, deterministic). Tests: expansion unit coverage (migrating slots, unrouted fallback via the default map, mis-sized volume map ignored, nullable retract keys in lockstep, slot machine index layout), an end-to-end stub-driven write-back asserting expanded slots, per-layer config-index resolution, the override merge incl. the nil-slot variant fallback, and re-apply stability, plus a real selector slice staying valid across re-apply. Suites green (libslic3r 48987/168, fff_print 633/60).
This commit is contained in:
@@ -1063,12 +1063,24 @@ bool ToolOrdering::cal_non_support_filaments(const PrintConfig &config,
|
||||
int find_count = 0;
|
||||
int find_first_filaments_count = 0;
|
||||
bool has_non_support = has_non_support_filament(config);
|
||||
for (const LayerTools &layer_tool : m_layer_tools) {
|
||||
for (const unsigned int &filament : layer_tool.extruders) {
|
||||
// The selector can move a filament between extruders per layer; resolve the extruder from
|
||||
// the published result then, so the first filament attributed to an extruder is one it
|
||||
// actually prints there. Static results keep the cross-layer filament_map arithmetic.
|
||||
const bool use_dynamic_map = m_nozzle_group_result.is_support_dynamic_nozzle_map() && m_nozzle_group_result.get_layer_count() > 0;
|
||||
auto extruder_for_filament = [&](unsigned int filament, size_t layer_idx) -> int {
|
||||
if (use_dynamic_map)
|
||||
return m_nozzle_group_result.get_extruder_id(static_cast<int>(filament), static_cast<int>(layer_idx));
|
||||
return config.filament_map.values[filament] - 1;
|
||||
};
|
||||
for (size_t layer_idx = 0; layer_idx < m_layer_tools.size(); ++layer_idx) {
|
||||
for (const unsigned int &filament : m_layer_tools[layer_idx].extruders) {
|
||||
//check first filament
|
||||
if (!config.filament_map.values.empty() && initial_filaments[config.filament_map.values[filament] - 1] == -1) {
|
||||
initial_filaments[config.filament_map.values[filament] - 1] = filament;
|
||||
find_first_filaments_count++;
|
||||
if (!config.filament_map.values.empty()) {
|
||||
const int extruder_id = extruder_for_filament(filament, layer_idx);
|
||||
if (extruder_id >= 0 && extruder_id < static_cast<int>(initial_filaments.size()) && initial_filaments[extruder_id] == -1) {
|
||||
initial_filaments[extruder_id] = filament;
|
||||
find_first_filaments_count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (has_non_support) {
|
||||
@@ -1083,8 +1095,9 @@ bool ToolOrdering::cal_non_support_filaments(const PrintConfig &config,
|
||||
if (config.filament_map.values.empty())
|
||||
return true;
|
||||
|
||||
if (initial_non_support_filaments[config.filament_map.values[filament] - 1] == -1) {
|
||||
initial_non_support_filaments[config.filament_map.values[filament] - 1] = filament;
|
||||
const int extruder_id = extruder_for_filament(filament, layer_idx);
|
||||
if (extruder_id >= 0 && extruder_id < static_cast<int>(initial_non_support_filaments.size()) && initial_non_support_filaments[extruder_id] == -1) {
|
||||
initial_non_support_filaments[extruder_id] = filament;
|
||||
find_count++;
|
||||
}
|
||||
|
||||
@@ -2080,17 +2093,15 @@ void ToolOrdering::reorder_extruders_for_minimum_flush_volume(bool reorder_first
|
||||
auto result = MultiNozzleUtils::LayeredNozzleGroupResult::create(nozzle_map_per_layer, grouping_context.nozzle_info.nozzle_list, used_filaments, filament_sequences);
|
||||
grouping_result = result ? *result : MultiNozzleUtils::LayeredNozzleGroupResult();
|
||||
|
||||
// Derive the extruder-level map for the stats path + config write-back.
|
||||
// Orca: the dynamic (per-layer) result carries no single volume/nozzle map, so only the
|
||||
// extruder map is written back here; the full per-nozzle config write-back
|
||||
// (a dedicated dynamic-map path) is a follow-up behind the dev flag.
|
||||
// Derive the extruder-level map for the stats path; the write-back resolves the
|
||||
// per-variant slots from the full grouping result itself.
|
||||
std::vector<int> derived_maps = grouping_result.get_extruder_map(false); // 1-based
|
||||
if (!derived_maps.empty()) {
|
||||
filament_maps = derived_maps;
|
||||
// A sequential per-object plan must not write its own map: the objects' plans are
|
||||
// stitched print-wide afterwards and written back once from there.
|
||||
if (not_sequential)
|
||||
m_print->update_filament_maps_to_config(filament_maps);
|
||||
m_print->update_to_config_by_nozzle_group_result(grouping_result);
|
||||
}
|
||||
std::transform(filament_maps.begin(), filament_maps.end(), filament_maps.begin(), [](int value) { return value - 1; });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user