mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-07-30 22:32:07 +00:00
feat(engine): wire the per-filament volume-map producer pipeline
- Print::update_filament_maps_to_config takes filament/volume/nozzle maps, backfills an empty volume map from extruder types, rebuilds filament_map_2, re-expands the per-filament variant arrays, and recomputes retract overrides keyed by resolved slots - grouping writes its result back in every non-sequential mode; manual multi-nozzle grouping validates the user mapping and raises a translatable error on deviation; the engine's concrete volume assignment is deliberately not merged yet (per-filament arrays are already consumed by filament id, so materializing High Flow now would change motion before the layer-aware resolvers land) - Print::apply treats the three map keys as engine outputs in auto modes (erased from the diff and adopted), compares them against used filaments in manual mode, and keeps the pre-expansion snapshot in sync with the late normalization pass so rebuilt headers reflect the sliced state instead of resurrecting stale values - volume/nozzle maps and extruder_nozzle_stats join the invalidation group of filament_map (wipe tower + skirt/brim) - PresetBundle composes full configs with an optional per-filament volume map (plate map, else defaults derived from each extruder's flow type); project config keeps the map sized across filament count changes - PartPlate stores per-plate volume/nozzle maps; Plater injects them at every slice-composition site (incl. g-code reload and wipe-tower estimation); BackgroundSlicingProcess reads engine results back to the plate in auto modes - per-filament map trust guards relaxed to size-match everywhere now that every producer sizes the map; single-filament explicit flow assignments are honored - tests: grouping volume maps stay concrete, merge semantics of update_used_filament_values, single-filament override honoring Motion g-code is byte-identical fleet-wide including Hybrid projects (19-fixture gate + repro determinism double-slice). Header deltas: the map keys now dump real values, and stale pre-normalization values (e.g. enable_prime_tower on single-used-filament prints) no longer leak into the config block.
This commit is contained in:
@@ -231,7 +231,20 @@ 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.
|
||||
}
|
||||
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
|
||||
// plate config the next apply overlays matches the engine's written-back state
|
||||
// (otherwise the full-config diff would invalidate the g-code on every apply).
|
||||
std::vector<int> f_nozzle_maps = m_fff_print->get_filament_nozzle_maps();
|
||||
m_current_plate->set_filament_nozzle_maps(f_nozzle_maps);
|
||||
}
|
||||
wxCommandEvent evt(m_event_slicing_completed_id);
|
||||
// Post the Slicing Finished message for the G-code viewer to update.
|
||||
// Passing the timestamp
|
||||
|
||||
@@ -319,6 +319,18 @@ std::vector<int> PartPlate::get_real_filament_maps(const DynamicConfig& g_config
|
||||
return g_maps;
|
||||
}
|
||||
|
||||
std::vector<int> PartPlate::get_real_filament_volume_maps(const DynamicConfig& g_config, bool* use_global_param) const
|
||||
{
|
||||
auto maps = get_filament_volume_maps();
|
||||
if (!maps.empty()) {
|
||||
if (use_global_param) { *use_global_param = false; }
|
||||
return maps;
|
||||
}
|
||||
auto g_maps = g_config.option<ConfigOptionInts>("filament_volume_map")->values;
|
||||
if (use_global_param) { *use_global_param = true; }
|
||||
return g_maps;
|
||||
}
|
||||
|
||||
FilamentMapMode PartPlate::get_real_filament_map_mode(const DynamicConfig& g_config, bool* use_global_param) const
|
||||
{
|
||||
auto mode = get_filament_map_mode();
|
||||
@@ -3506,8 +3518,16 @@ int PartPlate::load_gcode_from_file(const std::string& filename)
|
||||
int ret = 0;
|
||||
|
||||
// process gcode
|
||||
auto& preset_bundle = wxGetApp().preset_bundle;
|
||||
std::vector<int> filament_maps = this->get_filament_maps();
|
||||
DynamicPrintConfig full_config = wxGetApp().preset_bundle->full_config(false, filament_maps);
|
||||
// Inject the plate's volume map (or the per-extruder defaults) exactly like the apply-time
|
||||
// composition, so the config applied over the loaded slice result matches the next
|
||||
// background-process apply and does not invalidate the embedded g-code.
|
||||
std::vector<int> f_volume_maps = this->get_filament_volume_maps();
|
||||
if (f_volume_maps.empty()) {
|
||||
f_volume_maps = preset_bundle->get_default_nozzle_volume_types_for_filaments(filament_maps);
|
||||
}
|
||||
DynamicPrintConfig full_config = preset_bundle->full_config(false, filament_maps, f_volume_maps);
|
||||
full_config.apply(m_config, true);
|
||||
m_print->apply(*m_model, full_config, false);
|
||||
//BBS: need to apply two times, for after the first apply, the m_print got its object,
|
||||
@@ -3814,6 +3834,40 @@ void PartPlate::clear_filament_map()
|
||||
m_config.erase("filament_map");
|
||||
}
|
||||
|
||||
std::vector<int> PartPlate::get_filament_volume_maps() const
|
||||
{
|
||||
std::string key = "filament_volume_map";
|
||||
if (m_config.has(key))
|
||||
return m_config.option<ConfigOptionInts>(key)->values;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void PartPlate::set_filament_volume_maps(const std::vector<int>& f_maps)
|
||||
{
|
||||
m_config.option<ConfigOptionInts>("filament_volume_map", true)->values = f_maps;
|
||||
}
|
||||
|
||||
void PartPlate::clear_filament_volume_map()
|
||||
{
|
||||
if (m_config.has("filament_volume_map"))
|
||||
m_config.erase("filament_volume_map");
|
||||
}
|
||||
|
||||
std::vector<int> PartPlate::get_filament_nozzle_maps() const
|
||||
{
|
||||
std::string key = "filament_nozzle_map";
|
||||
if (m_config.has(key))
|
||||
return m_config.option<ConfigOptionInts>(key)->values;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void PartPlate::set_filament_nozzle_maps(const std::vector<int>& f_maps)
|
||||
{
|
||||
m_config.option<ConfigOptionInts>("filament_nozzle_map", true)->values = f_maps;
|
||||
}
|
||||
|
||||
void PartPlate::clear_filament_map_mode()
|
||||
{
|
||||
if (m_config.has("filament_map_mode"))
|
||||
@@ -4247,7 +4301,14 @@ void PartPlateList::set_default_wipe_tower_pos_for_plate(int plate_idx, bool ini
|
||||
coordf_t plate_bbox_y_max_local_coord = plate_bbox_2d.max(1) - plate_origin(1);
|
||||
|
||||
std::vector<int> filament_maps = part_plate->get_real_filament_maps(proj_cfg);
|
||||
DynamicPrintConfig full_config = wxGetApp().preset_bundle->full_config(false, filament_maps);
|
||||
// Keep this composition consistent with the apply-time injection (plate volume map, else
|
||||
// per-extruder defaults); the config below currently only feeds scalar reads, but a
|
||||
// divergent volume map would silently mis-resolve any future per-filament read here.
|
||||
std::vector<int> f_volume_maps = part_plate->get_filament_volume_maps();
|
||||
if (f_volume_maps.empty()) {
|
||||
f_volume_maps = wxGetApp().preset_bundle->get_default_nozzle_volume_types_for_filaments(filament_maps);
|
||||
}
|
||||
DynamicPrintConfig full_config = wxGetApp().preset_bundle->full_config(false, filament_maps, f_volume_maps);
|
||||
const DynamicPrintConfig &print_cfg = wxGetApp().preset_bundle->prints.get_edited_preset().config;
|
||||
float w = dynamic_cast<const ConfigOptionFloat *>(print_cfg.option("prime_tower_width"))->value;
|
||||
float v = dynamic_cast<const ConfigOptionFloat *>(full_config.option("prime_volume"))->value;
|
||||
|
||||
@@ -253,6 +253,7 @@ public:
|
||||
PrintSequence get_real_print_seq(bool* plate_same_as_global=nullptr) const;
|
||||
|
||||
std::vector<int> get_real_filament_maps(const DynamicConfig& g_config, bool* use_global_param = nullptr)const;
|
||||
std::vector<int> get_real_filament_volume_maps(const DynamicConfig& g_config, bool* use_global_param = nullptr) const;
|
||||
FilamentMapMode get_real_filament_map_mode(const DynamicConfig& g_config,bool * use_global_param = nullptr) const;
|
||||
|
||||
FilamentMapMode get_filament_map_mode() const;
|
||||
@@ -262,6 +263,15 @@ public:
|
||||
std::vector<int> get_filament_maps() const;
|
||||
void set_filament_maps(const std::vector<int>& f_maps);
|
||||
|
||||
// per-filament nozzle-volume choice (NozzleVolumeType values, 0 based filament ids)
|
||||
std::vector<int> get_filament_volume_maps() const;
|
||||
void set_filament_volume_maps(const std::vector<int>& f_maps);
|
||||
void clear_filament_volume_map();
|
||||
|
||||
// per-filament nozzle-group choice (0 based filament and nozzle ids)
|
||||
std::vector<int> get_filament_nozzle_maps() const;
|
||||
void set_filament_nozzle_maps(const std::vector<int>& f_maps);
|
||||
|
||||
void clear_filament_map();
|
||||
void clear_filament_map_mode();
|
||||
|
||||
|
||||
@@ -8818,7 +8818,11 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool
|
||||
if (preset_bundle->get_printer_extruder_count() > 1) {
|
||||
PartPlate* cur_plate = background_process.get_current_plate();
|
||||
std::vector<int> f_maps = cur_plate->get_real_filament_maps(preset_bundle->project_config);
|
||||
invalidated = background_process.apply(this->model, preset_bundle->full_config(false, f_maps));
|
||||
std::vector<int> f_volume_maps = cur_plate->get_filament_volume_maps();
|
||||
if (f_volume_maps.empty()) {
|
||||
f_volume_maps = preset_bundle->get_default_nozzle_volume_types_for_filaments(f_maps);
|
||||
}
|
||||
invalidated = background_process.apply(this->model, preset_bundle->full_config(false, f_maps, f_volume_maps));
|
||||
background_process.fff_print()->set_extruder_filament_info(get_extruder_filament_info());
|
||||
}
|
||||
else
|
||||
@@ -18326,7 +18330,11 @@ void Plater::apply_background_progress()
|
||||
Print::ApplyStatus invalidated;
|
||||
if (preset_bundle->get_printer_extruder_count() > 1) {
|
||||
std::vector<int> f_maps = part_plate->get_real_filament_maps(preset_bundle->project_config);
|
||||
invalidated = p->background_process.apply(this->model(), preset_bundle->full_config(false, f_maps));
|
||||
std::vector<int> f_volume_maps = part_plate->get_filament_volume_maps();
|
||||
if (f_volume_maps.empty()) {
|
||||
f_volume_maps = preset_bundle->get_default_nozzle_volume_types_for_filaments(f_maps);
|
||||
}
|
||||
invalidated = p->background_process.apply(this->model(), preset_bundle->full_config(false, f_maps, f_volume_maps));
|
||||
}
|
||||
else
|
||||
invalidated = p->background_process.apply(this->model(), preset_bundle->full_config(false));
|
||||
@@ -18371,7 +18379,11 @@ int Plater::select_plate(int plate_index, bool need_slice)
|
||||
//always apply the current plate's print
|
||||
if (preset_bundle->get_printer_extruder_count() > 1) {
|
||||
std::vector<int> f_maps = part_plate->get_real_filament_maps(preset_bundle->project_config);
|
||||
invalidated = p->background_process.apply(this->model(), preset_bundle->full_config(false, f_maps));
|
||||
std::vector<int> f_volume_maps = part_plate->get_filament_volume_maps();
|
||||
if (f_volume_maps.empty()) {
|
||||
f_volume_maps = preset_bundle->get_default_nozzle_volume_types_for_filaments(f_maps);
|
||||
}
|
||||
invalidated = p->background_process.apply(this->model(), preset_bundle->full_config(false, f_maps, f_volume_maps));
|
||||
}
|
||||
else
|
||||
invalidated = p->background_process.apply(this->model(), preset_bundle->full_config(false));
|
||||
@@ -18792,7 +18804,11 @@ int Plater::select_plate_by_hover_id(int hover_id, bool right_click, bool isModi
|
||||
//always apply the current plate's print
|
||||
if (preset_bundle->get_printer_extruder_count() > 1) {
|
||||
std::vector<int> f_maps = part_plate->get_real_filament_maps(preset_bundle->project_config);
|
||||
invalidated = p->background_process.apply(this->model(), preset_bundle->full_config(false, f_maps));
|
||||
std::vector<int> f_volume_maps = part_plate->get_filament_volume_maps();
|
||||
if (f_volume_maps.empty()) {
|
||||
f_volume_maps = preset_bundle->get_default_nozzle_volume_types_for_filaments(f_maps);
|
||||
}
|
||||
invalidated = p->background_process.apply(this->model(), preset_bundle->full_config(false, f_maps, f_volume_maps));
|
||||
}
|
||||
else
|
||||
invalidated = p->background_process.apply(this->model(), preset_bundle->full_config(false));
|
||||
|
||||
Reference in New Issue
Block a user