feat(gcode): resolve per-filament variant slots per layer

- the g-code writer tracks the current layer id and resolves
  FILAMENT_CONFIG/NOZZLE_CONFIG (plus every non-macro variant lookup,
  toolchange placeholder scalars, and the change-filament flush
  overrides) through Print's per-filament, per-layer config-index
  resolvers instead of the filament->extruder collapse
- update_layer_related_config refreshes the per-layer
  extruder/volume/nozzle maps in the writer config;
  update_placeholder_parser_with_variant_params remaps the
  filament-variant arrays into filament-id space for custom g-code
  (Orca's flush placeholder computation moves inside it)
- the engine's concrete per-filament volume assignment now merges into
  the config write-back (the temporary hold from the producer commit
  is lifted together with these consumers), and the background process
  reads the computed volume map back to the plate
- append_full_config dumps the resolved filament_map_2 slots
- update_used_filament_values gains a bounds guard
- tests: per-filament Hybrid slot resolution + null-result fallback

Result: on a Hybrid extruder, each filament's features slice with its
assigned sub-nozzle's variant values (speeds, volumetric limits,
retraction). Verified on a 4-filament H2C Hybrid project: outer walls
split into three feedrate populations (30/50/200 mm/s), toolpath
geometry byte-identical, deterministic across repeated slices. All 18
non-Hybrid reference fixtures stay byte-identical except the
filament_map_2 header value now showing the real slot. Auto grouping
ties (multiple zero-flush perfect matchings) may pick a different
filament-to-nozzle isolation than other slicers; verified co-optimal.
This commit is contained in:
SoftFever
2026-07-11 15:00:33 +08:00
parent 03a704df7c
commit 21b46044d0
8 changed files with 312 additions and 107 deletions

View File

@@ -231,12 +231,12 @@ void BackgroundSlicingProcess::process_fff()
if (m_current_plate->get_real_filament_map_mode(preset_bundle.project_config) < FilamentMapMode::fmmManual) {
std::vector<int> f_maps = m_fff_print->get_filament_maps();
m_current_plate->set_filament_maps(f_maps);
// Orca: the volume map is not read back to the plate yet. The engine's concrete
// volume assignment is not written into the print config until the layer-aware
// g-code resolvers consume it (see the ToolOrdering write-back), so the print-side
// value here is just the injected plate-or-default map echoed back; persisting it
// would freeze the per-extruder defaults (including the transient Hybrid seed) into
// the plate and the saved project. Restore together with the write-back merge.
// The engine's concrete per-filament volume assignment is merged into the print
// config by the ToolOrdering write-back; reading it back keeps the plate config the
// next apply overlays equal to the written-back state (no diff, no re-invalidation)
// and persists the auto result (always concrete Std/HF, never the Hybrid seed).
std::vector<int> f_volume_maps = m_fff_print->get_filament_volume_maps();
m_current_plate->set_filament_volume_maps(f_volume_maps);
}
if (m_current_plate->get_real_filament_map_mode(preset_bundle.project_config) != FilamentMapMode::fmmNozzleManual) {
// The engine-resolved nozzle map is read back for every non-nozzle-manual mode so the