mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-28 03:11:47 +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:
@@ -10467,6 +10467,9 @@ msgstr ""
|
|||||||
msgid "Grouping error: "
|
msgid "Grouping error: "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Group error in manual mode. Please check nozzle count or regroup."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid " can not be placed in the "
|
msgid " can not be placed in the "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -4512,8 +4512,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
|||||||
if (m_curr_plater){
|
if (m_curr_plater){
|
||||||
auto filament_volume_map = get_vector_from_string(value);
|
auto filament_volume_map = get_vector_from_string(value);
|
||||||
for (size_t idx = 0; idx < filament_volume_map.size(); ++idx) {
|
for (size_t idx = 0; idx < filament_volume_map.size(); ++idx) {
|
||||||
// Only Standard(0)/High Flow(1) are currently supported; clamp any higher
|
// The map feeds per-filament slot resolution and grouping. Clamp any
|
||||||
// volume-type (TPU High Flow/Hybrid) back to Standard until they are wired in.
|
// higher volume-type back to Standard(0) on load: Hybrid(2) is only an
|
||||||
|
// in-memory grouping seed that is never persisted, and TPU High Flow(3)
|
||||||
|
// is clamped with the same information loss on every load.
|
||||||
if (filament_volume_map[idx] > 1) {
|
if (filament_volume_map[idx] > 1) {
|
||||||
filament_volume_map[idx] = 0;
|
filament_volume_map[idx] = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1332,12 +1332,12 @@ static FilamentGroupContext build_filament_group_context(
|
|||||||
context.group_info.has_filament_switcher = has_filament_switcher;
|
context.group_info.has_filament_switcher = has_filament_switcher;
|
||||||
|
|
||||||
// hybrid flow means no special per-filament nozzle-volume request.
|
// hybrid flow means no special per-filament nozzle-volume request.
|
||||||
// Orca: in manual mode the config's per-filament volume map is honoured only when a producer
|
// Orca: honour the config's per-filament volume map only when it is sized to the filament
|
||||||
// sized it to a multi-filament count (the trust guard used by
|
// count. The full-config producers (PresetBundle injection, engine write-back) always size
|
||||||
// update_values_to_printer_extruders_for_multiple_filaments): the registered default is a
|
// it; a mis-sized map (stale project value, CLI runs until the per-filament synthesis lands
|
||||||
// 1-element vector ({Standard}) that a single-filament count cannot tell apart from a real
|
// there) must not displace the hybrid fallback rebuild_nozzle_unprintables relies on, nor be
|
||||||
// map, and it must not displace the hybrid fallback rebuild_nozzle_unprintables relies on.
|
// indexed out of bounds.
|
||||||
if (mode == FilamentMapMode::fmmManual && filament_nums > 1 &&
|
if (mode == FilamentMapMode::fmmManual &&
|
||||||
print_config.filament_volume_map.values.size() == filament_nums)
|
print_config.filament_volume_map.values.size() == filament_nums)
|
||||||
context.group_info.filament_volume_map = print_config.filament_volume_map.values;
|
context.group_info.filament_volume_map = print_config.filament_volume_map.values;
|
||||||
else
|
else
|
||||||
@@ -1487,12 +1487,12 @@ MultiNozzleUtils::LayeredNozzleGroupResult ToolOrdering::get_recommended_filamen
|
|||||||
std::transform(manual_filament_map.begin(), manual_filament_map.end(), manual_filament_map.begin(), [](int v) { return v - 1; });
|
std::transform(manual_filament_map.begin(), manual_filament_map.end(), manual_filament_map.begin(), [](int v) { return v - 1; });
|
||||||
float diameter = print_config.nozzle_diameter.values.empty() ? 0.4f : (float)print_config.nozzle_diameter.values.front();
|
float diameter = print_config.nozzle_diameter.values.empty() ? 0.4f : (float)print_config.nozzle_diameter.values.front();
|
||||||
// Orca: create() indexes the volume/nozzle maps per used filament with no bounds check, so
|
// Orca: create() indexes the volume/nozzle maps per used filament with no bounds check, so
|
||||||
// pass them only when a producer sized them to a multi-filament count — the registered
|
// pass them only when a producer sized them to the filament count (mis-sized maps can
|
||||||
// 1-element defaults are indistinguishable by size from a real single-filament map.
|
// arrive from stale projects or CLI runs until the per-filament synthesis lands there).
|
||||||
// Without valid maps the fully-manual request cannot be honoured; return the empty result,
|
// Without valid maps the fully-manual request cannot be honoured; return the empty result,
|
||||||
// the same failure an unsatisfiable create() yields.
|
// the same failure an unsatisfiable create() yields.
|
||||||
std::optional<LayeredNozzleGroupResult> nozzle_result;
|
std::optional<LayeredNozzleGroupResult> nozzle_result;
|
||||||
if (filament_nums > 1 && print_config.filament_volume_map.values.size() == filament_nums &&
|
if (print_config.filament_volume_map.values.size() == filament_nums &&
|
||||||
print_config.filament_nozzle_map.values.size() == filament_nums)
|
print_config.filament_nozzle_map.values.size() == filament_nums)
|
||||||
nozzle_result = LayeredNozzleGroupResult::create(used_filaments, manual_filament_map, print_config.filament_volume_map.values, print_config.filament_nozzle_map.values, get_extruder_nozzle_stats(print_config.extruder_nozzle_stats.values), diameter);
|
nozzle_result = LayeredNozzleGroupResult::create(used_filaments, manual_filament_map, print_config.filament_volume_map.values, print_config.filament_nozzle_map.values, get_extruder_nozzle_stats(print_config.extruder_nozzle_stats.values), diameter);
|
||||||
if (!nozzle_result)
|
if (!nozzle_result)
|
||||||
@@ -1556,7 +1556,21 @@ MultiNozzleUtils::LayeredNozzleGroupResult ToolOrdering::get_recommended_filamen
|
|||||||
|
|
||||||
if (has_multiple_nozzle) {
|
if (has_multiple_nozzle) {
|
||||||
auto result_opt = LayeredNozzleGroupResult::create(ret, context.nozzle_info.nozzle_list, used_filaments);
|
auto result_opt = LayeredNozzleGroupResult::create(ret, context.nozzle_info.nozzle_list, used_filaments);
|
||||||
return result_opt ? *result_opt : LayeredNozzleGroupResult();
|
if (!result_opt)
|
||||||
|
return LayeredNozzleGroupResult();
|
||||||
|
auto result = *result_opt;
|
||||||
|
if (mode == FilamentMapMode::fmmManual) {
|
||||||
|
// Manual grouping must reproduce the user's filament->extruder map exactly; a
|
||||||
|
// deviation means the requested assignment cannot be satisfied by the nozzle
|
||||||
|
// inventory, which must surface as a slicing error instead of silently regrouping.
|
||||||
|
auto result_map = result.get_extruder_map();
|
||||||
|
for (auto fid : used_filaments) {
|
||||||
|
if (result_map[fid] != print_config.filament_map.values[fid] - 1) {
|
||||||
|
throw Slic3r::RuntimeError(_L("Group error in manual mode. Please check nozzle count or regroup."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1617,11 +1631,11 @@ static MultiNozzleUtils::LayeredNozzleGroupResult build_group_result_from_map(
|
|||||||
const size_t filament_nums = print_config.filament_colour.values.size();
|
const size_t filament_nums = print_config.filament_colour.values.size();
|
||||||
const bool has_multiple_nozzle = std::any_of(print_config.extruder_max_nozzle_count.values.begin(), print_config.extruder_max_nozzle_count.values.end(),
|
const bool has_multiple_nozzle = std::any_of(print_config.extruder_max_nozzle_count.values.begin(), print_config.extruder_max_nozzle_count.values.end(),
|
||||||
[](int v) { return v > 1; });
|
[](int v) { return v > 1; });
|
||||||
// Orca: same trust guard as the manual grouping paths — create() indexes the volume/nozzle
|
// Orca: same sizing guard as the manual grouping paths — create() indexes the volume/nozzle
|
||||||
// maps per used filament with no bounds check, and the registered 1-element defaults must not
|
// maps per used filament with no bounds check, so only maps sized to the filament count are
|
||||||
// be mistaken for a real single-filament map. Unsized maps fall through to the extruder-level
|
// trusted (mis-sized maps can arrive from stale projects or CLI runs until the per-filament
|
||||||
// wrap below.
|
// synthesis lands there). Unsized maps fall through to the extruder-level wrap below.
|
||||||
if (has_multiple_nozzle && filament_nums > 1 &&
|
if (has_multiple_nozzle &&
|
||||||
print_config.filament_volume_map.values.size() == filament_nums &&
|
print_config.filament_volume_map.values.size() == filament_nums &&
|
||||||
print_config.filament_nozzle_map.values.size() == filament_nums) {
|
print_config.filament_nozzle_map.values.size() == filament_nums) {
|
||||||
float diameter = print_config.nozzle_diameter.values.empty() ? 0.4f : static_cast<float>(print_config.nozzle_diameter.values.front());
|
float diameter = print_config.nozzle_diameter.values.empty() ? 0.4f : static_cast<float>(print_config.nozzle_diameter.values.front());
|
||||||
@@ -2042,8 +2056,10 @@ 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);
|
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();
|
grouping_result = result ? *result : MultiNozzleUtils::LayeredNozzleGroupResult();
|
||||||
|
|
||||||
// Derive the extruder-level map (0-based) for the stats path + config write-back. The full
|
// Derive the extruder-level map for the stats path + config write-back.
|
||||||
// per-nozzle config write-back is not yet wired.
|
// 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.
|
||||||
std::vector<int> derived_maps = grouping_result.get_extruder_map(false); // 1-based
|
std::vector<int> derived_maps = grouping_result.get_extruder_map(false); // 1-based
|
||||||
if (!derived_maps.empty()) {
|
if (!derived_maps.empty()) {
|
||||||
filament_maps = derived_maps;
|
filament_maps = derived_maps;
|
||||||
@@ -2060,11 +2076,34 @@ void ToolOrdering::reorder_extruders_for_minimum_flush_volume(bool reorder_first
|
|||||||
if (derived_maps.empty())
|
if (derived_maps.empty())
|
||||||
return;
|
return;
|
||||||
filament_maps = derived_maps;
|
filament_maps = derived_maps;
|
||||||
m_print->update_filament_maps_to_config(filament_maps);
|
|
||||||
} else if (!derived_maps.empty()) {
|
} else if (!derived_maps.empty()) {
|
||||||
// Manual modes: the result mirrors the user's config map; adopt it for consistency.
|
// Manual modes: the result mirrors the user's config map; adopt it for consistency.
|
||||||
filament_maps = derived_maps;
|
filament_maps = derived_maps;
|
||||||
}
|
}
|
||||||
|
// Write the maps back for every mode: used filaments adopt the engine's extruder/nozzle
|
||||||
|
// choice, unused ones keep their config assignment. In manual modes the extruder map
|
||||||
|
// mirrors the user's map (a deviation throws in get_recommended_filament_maps).
|
||||||
|
if (!derived_maps.empty()) {
|
||||||
|
// Orca: the config maps are the merge base; fall back to a synthesized base when no
|
||||||
|
// producer sized them to the filament count (CLI runs until the per-filament
|
||||||
|
// synthesis lands there), where indexing per filament would run out of bounds.
|
||||||
|
std::vector<int> base_filament_map = print_config->filament_map.values;
|
||||||
|
if (base_filament_map.size() != derived_maps.size())
|
||||||
|
base_filament_map.assign(derived_maps.size(), 1);
|
||||||
|
std::vector<int> base_volume_map = print_config->filament_volume_map.values;
|
||||||
|
if (base_volume_map.size() != derived_maps.size())
|
||||||
|
base_volume_map.assign(derived_maps.size(), (int)nvtStandard);
|
||||||
|
// Orca: the engine's concrete per-filament volume assignment (get_volume_map()) is
|
||||||
|
// deliberately NOT merged into the write-back yet. The write-back re-expands the
|
||||||
|
// per-filament filament_* arrays from these maps, and those arrays are already
|
||||||
|
// consumed by filament id, so materializing a High Flow assignment here would alter
|
||||||
|
// motion g-code before the layer-aware g-code resolvers consume the assignment.
|
||||||
|
// Until those consumers land, the config keeps its own (GUI-injected or project)
|
||||||
|
// volume map, size-corrected above.
|
||||||
|
m_print->update_filament_maps_to_config(FilamentGroupUtils::update_used_filament_values(base_filament_map, derived_maps, used_filaments),
|
||||||
|
base_volume_map,
|
||||||
|
grouping_result.get_nozzle_map());
|
||||||
|
}
|
||||||
std::transform(filament_maps.begin(), filament_maps.end(), filament_maps.begin(), [](int value) { return value - 1; });
|
std::transform(filament_maps.begin(), filament_maps.end(), filament_maps.begin(), [](int value) { return value - 1; });
|
||||||
|
|
||||||
if (m_print->is_BBL_printer())
|
if (m_print->is_BBL_printer())
|
||||||
|
|||||||
@@ -58,6 +58,9 @@ static std::vector<std::string> s_project_options {
|
|||||||
"nozzle_volume_type",
|
"nozzle_volume_type",
|
||||||
"filament_map_mode",
|
"filament_map_mode",
|
||||||
"filament_map",
|
"filament_map",
|
||||||
|
// Per-filament nozzle-volume choice; project-level like filament_map so the per-filament
|
||||||
|
// slot resolution survives preset switches.
|
||||||
|
"filament_volume_map",
|
||||||
// Filament Track Switch device state: whether the switch is installed and ready, and
|
// Filament Track Switch device state: whether the switch is installed and ready, and
|
||||||
// whether dynamic per-nozzle filament mapping is active. Persisted with the project and
|
// whether dynamic per-nozzle filament mapping is active. Persisted with the project and
|
||||||
// restored from a saved 3mf; reset to false on load and set true only by live device sync.
|
// restored from a saved 3mf; reset to false on load and set true only by live device sync.
|
||||||
@@ -79,7 +82,8 @@ DynamicPrintConfig PresetBundle::construct_full_config(
|
|||||||
const DynamicPrintConfig& project_config,
|
const DynamicPrintConfig& project_config,
|
||||||
std::vector<Preset>& in_filament_presets,
|
std::vector<Preset>& in_filament_presets,
|
||||||
bool apply_extruder,
|
bool apply_extruder,
|
||||||
std::optional<std::vector<int>> filament_maps_new)
|
std::optional<std::vector<int>> filament_maps_new,
|
||||||
|
std::optional<std::vector<int>> filament_volume_maps_new)
|
||||||
{
|
{
|
||||||
DynamicPrintConfig &printer_config = in_printer_preset.config;
|
DynamicPrintConfig &printer_config = in_printer_preset.config;
|
||||||
DynamicPrintConfig &print_config = in_print_preset.config;
|
DynamicPrintConfig &print_config = in_print_preset.config;
|
||||||
@@ -94,12 +98,23 @@ DynamicPrintConfig PresetBundle::construct_full_config(
|
|||||||
size_t num_filaments = in_filament_presets.size();
|
size_t num_filaments = in_filament_presets.size();
|
||||||
|
|
||||||
std::vector<int> filament_maps = out.option<ConfigOptionInts>("filament_map")->values;
|
std::vector<int> filament_maps = out.option<ConfigOptionInts>("filament_map")->values;
|
||||||
|
std::vector<int> filament_volume_maps(num_filaments, (int)nvtStandard);
|
||||||
|
|
||||||
|
ConfigOptionInts* filament_volume_map_opt = out.option<ConfigOptionInts>("filament_volume_map");
|
||||||
if (filament_maps_new.has_value())
|
if (filament_maps_new.has_value())
|
||||||
filament_maps = *filament_maps_new;
|
filament_maps = *filament_maps_new;
|
||||||
|
if (filament_volume_maps_new.has_value())
|
||||||
|
filament_volume_maps = *filament_volume_maps_new;
|
||||||
|
else if (filament_volume_map_opt && filament_volume_map_opt->values.size() == num_filaments)
|
||||||
|
filament_volume_maps = filament_volume_map_opt->values;
|
||||||
|
|
||||||
// in some middle state, they may be different
|
// in some middle state, they may be different
|
||||||
if (filament_maps.size() != num_filaments) {
|
if (filament_maps.size() != num_filaments) {
|
||||||
filament_maps.resize(num_filaments, 1);
|
filament_maps.resize(num_filaments, 1);
|
||||||
}
|
}
|
||||||
|
if (filament_volume_maps.size() != num_filaments) {
|
||||||
|
filament_volume_maps.resize(num_filaments, nvtStandard);
|
||||||
|
}
|
||||||
|
|
||||||
auto *extruder_diameter = dynamic_cast<const ConfigOptionFloats *>(out.option("nozzle_diameter"));
|
auto *extruder_diameter = dynamic_cast<const ConfigOptionFloats *>(out.option("nozzle_diameter"));
|
||||||
// Collect the "compatible_printers_condition" and "inherits" values over all presets (print, filaments, printers) into a single vector.
|
// Collect the "compatible_printers_condition" and "inherits" values over all presets (print, filaments, printers) into a single vector.
|
||||||
@@ -147,7 +162,7 @@ DynamicPrintConfig PresetBundle::construct_full_config(
|
|||||||
// BBS: update filament config related with variants
|
// BBS: update filament config related with variants
|
||||||
DynamicPrintConfig filament_config = in_filament_presets[0].config;
|
DynamicPrintConfig filament_config = in_filament_presets[0].config;
|
||||||
if (apply_extruder && ((extruder_count > 1) || different_extruder))
|
if (apply_extruder && ((extruder_count > 1) || different_extruder))
|
||||||
filament_config.update_values_to_printer_extruders(out, extruder_count, extruder_volume_type_count, nozzle_volume_types, filament_options_with_variant, "", "filament_extruder_variant", 1, filament_maps[0]);
|
filament_config.update_values_to_printer_extruders(out, extruder_count, extruder_volume_type_count, nozzle_volume_types, filament_options_with_variant, "", "filament_extruder_variant", 1, filament_maps[0], (NozzleVolumeType)filament_volume_maps[0]);
|
||||||
out.apply(filament_config);
|
out.apply(filament_config);
|
||||||
compatible_printers_condition.emplace_back(in_filament_presets[0].compatible_printers_condition());
|
compatible_printers_condition.emplace_back(in_filament_presets[0].compatible_printers_condition());
|
||||||
compatible_prints_condition.emplace_back(in_filament_presets[0].compatible_prints_condition());
|
compatible_prints_condition.emplace_back(in_filament_presets[0].compatible_prints_condition());
|
||||||
@@ -171,7 +186,7 @@ DynamicPrintConfig PresetBundle::construct_full_config(
|
|||||||
for (size_t i = 0; i < num_filaments; ++i) {
|
for (size_t i = 0; i < num_filaments; ++i) {
|
||||||
filament_temp_configs[i] = *(filament_configs[i]);
|
filament_temp_configs[i] = *(filament_configs[i]);
|
||||||
if (apply_extruder && ((extruder_count > 1) || different_extruder))
|
if (apply_extruder && ((extruder_count > 1) || different_extruder))
|
||||||
filament_temp_configs[i].update_values_to_printer_extruders(out, extruder_count, extruder_volume_type_count, nozzle_volume_types, filament_options_with_variant, "", "filament_extruder_variant", 1, filament_maps[i]);
|
filament_temp_configs[i].update_values_to_printer_extruders(out, extruder_count, extruder_volume_type_count, nozzle_volume_types, filament_options_with_variant, "", "filament_extruder_variant", 1, filament_maps[i], (NozzleVolumeType)filament_volume_maps[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// loop through options and apply them to the resulting config.
|
// loop through options and apply them to the resulting config.
|
||||||
@@ -246,6 +261,7 @@ DynamicPrintConfig PresetBundle::construct_full_config(
|
|||||||
out.option<ConfigOptionString>("printer_settings_id", true)->value = in_printer_preset.name;
|
out.option<ConfigOptionString>("printer_settings_id", true)->value = in_printer_preset.name;
|
||||||
out.option<ConfigOptionStrings>("filament_ids", true)->values = filament_ids;
|
out.option<ConfigOptionStrings>("filament_ids", true)->values = filament_ids;
|
||||||
out.option<ConfigOptionInts>("filament_map", true)->values = filament_maps;
|
out.option<ConfigOptionInts>("filament_map", true)->values = filament_maps;
|
||||||
|
out.option<ConfigOptionInts>("filament_volume_map", true)->values = filament_volume_maps;
|
||||||
|
|
||||||
auto add_if_some_non_empty = [&out](std::vector<std::string> &&values, const std::string &key) {
|
auto add_if_some_non_empty = [&out](std::vector<std::string> &&values, const std::string &key) {
|
||||||
bool nonempty = false;
|
bool nonempty = false;
|
||||||
@@ -2701,6 +2717,9 @@ void PresetBundle::update_selections(AppConfig &config)
|
|||||||
std::vector<int> filament_maps(filament_colors.size(), 1);
|
std::vector<int> filament_maps(filament_colors.size(), 1);
|
||||||
project_config.option<ConfigOptionInts>("filament_map")->values = filament_maps;
|
project_config.option<ConfigOptionInts>("filament_map")->values = filament_maps;
|
||||||
|
|
||||||
|
std::vector<int> filament_volume_maps(filament_colors.size(), static_cast<int>(NozzleVolumeType::nvtStandard));
|
||||||
|
project_config.option<ConfigOptionInts>("filament_volume_map")->values = filament_volume_maps;
|
||||||
|
|
||||||
std::vector<std::string> extruder_ams_count_str;
|
std::vector<std::string> extruder_ams_count_str;
|
||||||
if (config.has_printer_setting(initial_printer_profile_name, "extruder_ams_count")) {
|
if (config.has_printer_setting(initial_printer_profile_name, "extruder_ams_count")) {
|
||||||
boost::algorithm::split(extruder_ams_count_str, config.get_printer_setting(initial_printer_profile_name, "extruder_ams_count"), boost::algorithm::is_any_of(","));
|
boost::algorithm::split(extruder_ams_count_str, config.get_printer_setting(initial_printer_profile_name, "extruder_ams_count"), boost::algorithm::is_any_of(","));
|
||||||
@@ -2845,6 +2864,9 @@ void PresetBundle::load_selections(AppConfig &config, const PresetPreferences& p
|
|||||||
std::vector<int> filament_maps(filament_colors.size(), 1);
|
std::vector<int> filament_maps(filament_colors.size(), 1);
|
||||||
project_config.option<ConfigOptionInts>("filament_map")->values = filament_maps;
|
project_config.option<ConfigOptionInts>("filament_map")->values = filament_maps;
|
||||||
|
|
||||||
|
std::vector<int> filament_volume_maps(filament_colors.size(), static_cast<int>(NozzleVolumeType::nvtStandard));
|
||||||
|
project_config.option<ConfigOptionInts>("filament_volume_map")->values = filament_volume_maps;
|
||||||
|
|
||||||
std::vector<std::string> extruder_ams_count_str;
|
std::vector<std::string> extruder_ams_count_str;
|
||||||
if (config.has_printer_setting(initial_printer_profile_name, "extruder_ams_count")) {
|
if (config.has_printer_setting(initial_printer_profile_name, "extruder_ams_count")) {
|
||||||
boost::algorithm::split(extruder_ams_count_str, config.get_printer_setting(initial_printer_profile_name, "extruder_ams_count"), boost::algorithm::is_any_of(","));
|
boost::algorithm::split(extruder_ams_count_str, config.get_printer_setting(initial_printer_profile_name, "extruder_ams_count"), boost::algorithm::is_any_of(","));
|
||||||
@@ -3021,7 +3043,7 @@ void PresetBundle::set_num_filaments(unsigned int n, std::vector<std::string> ne
|
|||||||
ConfigOptionStrings *filament_multi_color = project_config.option<ConfigOptionStrings>("filament_multi_colour");
|
ConfigOptionStrings *filament_multi_color = project_config.option<ConfigOptionStrings>("filament_multi_colour");
|
||||||
ConfigOptionStrings* filament_color_type = project_config.option<ConfigOptionStrings>("filament_colour_type");
|
ConfigOptionStrings* filament_color_type = project_config.option<ConfigOptionStrings>("filament_colour_type");
|
||||||
ConfigOptionInts* filament_map = project_config.option<ConfigOptionInts>("filament_map");
|
ConfigOptionInts* filament_map = project_config.option<ConfigOptionInts>("filament_map");
|
||||||
|
ConfigOptionInts* filament_volume_map = project_config.option<ConfigOptionInts>("filament_volume_map");
|
||||||
|
|
||||||
filament_color->resize(n);
|
filament_color->resize(n);
|
||||||
// Sync filament multi colour
|
// Sync filament multi colour
|
||||||
@@ -3031,6 +3053,7 @@ void PresetBundle::set_num_filaments(unsigned int n, std::vector<std::string> ne
|
|||||||
}
|
}
|
||||||
filament_color_type->resize(n);
|
filament_color_type->resize(n);
|
||||||
filament_map->values.resize(n, 1);
|
filament_map->values.resize(n, 1);
|
||||||
|
filament_volume_map->values.resize(n, static_cast<int>(NozzleVolumeType::nvtStandard));
|
||||||
ams_multi_color_filment.resize(n);
|
ams_multi_color_filment.resize(n);
|
||||||
|
|
||||||
// BBS set new filament color to new_color
|
// BBS set new filament color to new_color
|
||||||
@@ -3058,7 +3081,7 @@ void PresetBundle::set_num_filaments(unsigned int n, std::string new_color)
|
|||||||
ConfigOptionStrings *filament_multi_color = project_config.option<ConfigOptionStrings>("filament_multi_colour");
|
ConfigOptionStrings *filament_multi_color = project_config.option<ConfigOptionStrings>("filament_multi_colour");
|
||||||
ConfigOptionStrings* filament_color_type = project_config.option<ConfigOptionStrings>("filament_colour_type");
|
ConfigOptionStrings* filament_color_type = project_config.option<ConfigOptionStrings>("filament_colour_type");
|
||||||
ConfigOptionInts* filament_map = project_config.option<ConfigOptionInts>("filament_map");
|
ConfigOptionInts* filament_map = project_config.option<ConfigOptionInts>("filament_map");
|
||||||
|
ConfigOptionInts* filament_volume_map = project_config.option<ConfigOptionInts>("filament_volume_map");
|
||||||
|
|
||||||
filament_color->resize(n);
|
filament_color->resize(n);
|
||||||
// Sync filament multi colour
|
// Sync filament multi colour
|
||||||
@@ -3068,6 +3091,7 @@ void PresetBundle::set_num_filaments(unsigned int n, std::string new_color)
|
|||||||
}
|
}
|
||||||
filament_color_type->resize(n);
|
filament_color_type->resize(n);
|
||||||
filament_map->values.resize(n, 1);
|
filament_map->values.resize(n, 1);
|
||||||
|
filament_volume_map->values.resize(n, static_cast<int>(NozzleVolumeType::nvtStandard));
|
||||||
ams_multi_color_filment.resize(n);
|
ams_multi_color_filment.resize(n);
|
||||||
|
|
||||||
//BBS set new filament color to new_color
|
//BBS set new filament color to new_color
|
||||||
@@ -3108,15 +3132,20 @@ void PresetBundle::update_num_filaments(unsigned int to_del_flament_id)
|
|||||||
ConfigOptionStrings *filament_multi_color = project_config.option<ConfigOptionStrings>("filament_multi_colour");
|
ConfigOptionStrings *filament_multi_color = project_config.option<ConfigOptionStrings>("filament_multi_colour");
|
||||||
ConfigOptionStrings *filament_color_type = project_config.option<ConfigOptionStrings>("filament_colour_type");
|
ConfigOptionStrings *filament_color_type = project_config.option<ConfigOptionStrings>("filament_colour_type");
|
||||||
ConfigOptionInts* filament_map = project_config.option<ConfigOptionInts>("filament_map");
|
ConfigOptionInts* filament_map = project_config.option<ConfigOptionInts>("filament_map");
|
||||||
|
ConfigOptionInts* filament_volume_map = project_config.option<ConfigOptionInts>("filament_volume_map");
|
||||||
if (filament_color->values.size() > to_del_flament_id) {
|
if (filament_color->values.size() > to_del_flament_id) {
|
||||||
filament_color->values.erase(filament_color->values.begin() + to_del_flament_id);
|
filament_color->values.erase(filament_color->values.begin() + to_del_flament_id);
|
||||||
if (filament_map->values.size() > to_del_flament_id) {
|
if (filament_map->values.size() > to_del_flament_id) {
|
||||||
filament_map->values.erase(filament_map->values.begin() + to_del_flament_id);
|
filament_map->values.erase(filament_map->values.begin() + to_del_flament_id);
|
||||||
}
|
}
|
||||||
|
if (filament_volume_map->values.size() > to_del_flament_id) {
|
||||||
|
filament_volume_map->values.erase(filament_volume_map->values.begin() + to_del_flament_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
filament_color->values.resize(to_del_flament_id);
|
filament_color->values.resize(to_del_flament_id);
|
||||||
filament_map->values.resize(to_del_flament_id, 1);
|
filament_map->values.resize(to_del_flament_id, 1);
|
||||||
|
filament_volume_map->values.resize(to_del_flament_id, static_cast<int>(NozzleVolumeType::nvtStandard));
|
||||||
}
|
}
|
||||||
|
|
||||||
// lambda function to erase or resize the container
|
// lambda function to erase or resize the container
|
||||||
@@ -3339,6 +3368,7 @@ unsigned int PresetBundle::sync_ams_list(std::vector<std::pair<DynamicPrintConfi
|
|||||||
ConfigOptionStrings *filament_color = project_config.option<ConfigOptionStrings>("filament_colour");
|
ConfigOptionStrings *filament_color = project_config.option<ConfigOptionStrings>("filament_colour");
|
||||||
ConfigOptionStrings *filament_color_type = project_config.option<ConfigOptionStrings>("filament_colour_type");
|
ConfigOptionStrings *filament_color_type = project_config.option<ConfigOptionStrings>("filament_colour_type");
|
||||||
ConfigOptionInts * filament_map = project_config.option<ConfigOptionInts>("filament_map");
|
ConfigOptionInts * filament_map = project_config.option<ConfigOptionInts>("filament_map");
|
||||||
|
ConfigOptionInts * filament_volume_map = project_config.option<ConfigOptionInts>("filament_volume_map");
|
||||||
if (color_only) {
|
if (color_only) {
|
||||||
auto get_map_index = [&ams_infos](const std::vector<AMSMapInfo> &infos, const AMSMapInfo &temp) {
|
auto get_map_index = [&ams_infos](const std::vector<AMSMapInfo> &infos, const AMSMapInfo &temp) {
|
||||||
for (int i = 0; i < infos.size(); i++) {
|
for (int i = 0; i < infos.size(); i++) {
|
||||||
@@ -3520,6 +3550,7 @@ unsigned int PresetBundle::sync_ams_list(std::vector<std::pair<DynamicPrintConfi
|
|||||||
ams_multi_color_filment = exist_multi_color_filment;
|
ams_multi_color_filment = exist_multi_color_filment;
|
||||||
this->filament_presets = exist_filament_presets;
|
this->filament_presets = exist_filament_presets;
|
||||||
filament_map->values.resize(exist_filament_presets.size(), 1);
|
filament_map->values.resize(exist_filament_presets.size(), 1);
|
||||||
|
filament_volume_map->values.resize(exist_filament_presets.size(), static_cast<int>(NozzleVolumeType::nvtStandard));
|
||||||
}
|
}
|
||||||
else {//overwrite;
|
else {//overwrite;
|
||||||
bool has_placeholders = std::any_of(ams_infos.begin(), ams_infos.end(),
|
bool has_placeholders = std::any_of(ams_infos.begin(), ams_infos.end(),
|
||||||
@@ -3574,12 +3605,14 @@ unsigned int PresetBundle::sync_ams_list(std::vector<std::pair<DynamicPrintConfi
|
|||||||
this->filament_presets = result_presets;
|
this->filament_presets = result_presets;
|
||||||
ams_multi_color_filment = result_multi_colors;
|
ams_multi_color_filment = result_multi_colors;
|
||||||
filament_map->values.resize(total, 1);
|
filament_map->values.resize(total, 1);
|
||||||
|
filament_volume_map->values.resize(total, static_cast<int>(NozzleVolumeType::nvtStandard));
|
||||||
} else {
|
} else {
|
||||||
// BBL: existing wholesale replace
|
// BBL: existing wholesale replace
|
||||||
filament_color->values = ams_filament_colors;
|
filament_color->values = ams_filament_colors;
|
||||||
filament_color_type->values = ams_filament_color_types;
|
filament_color_type->values = ams_filament_color_types;
|
||||||
this->filament_presets = ams_filament_presets;
|
this->filament_presets = ams_filament_presets;
|
||||||
filament_map->values.resize(ams_filament_colors.size(), 1);
|
filament_map->values.resize(ams_filament_colors.size(), 1);
|
||||||
|
filament_volume_map->values.resize(ams_filament_colors.size(), static_cast<int>(NozzleVolumeType::nvtStandard));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& print_config = this->prints.get_edited_preset().config;
|
auto& print_config = this->prints.get_edited_preset().config;
|
||||||
@@ -3882,10 +3915,26 @@ bool PresetBundle::support_different_extruders() const
|
|||||||
return supported;
|
return supported;
|
||||||
}
|
}
|
||||||
|
|
||||||
DynamicPrintConfig PresetBundle::full_config(bool apply_extruder, std::optional<std::vector<int>>filament_maps) const
|
std::vector<int> PresetBundle::get_default_nozzle_volume_types_for_filaments(std::vector<int>& f_maps)
|
||||||
|
{
|
||||||
|
std::vector<int> result;
|
||||||
|
int filament_count = f_maps.size();
|
||||||
|
result.resize(filament_count, static_cast<int>(NozzleVolumeType::nvtStandard));
|
||||||
|
|
||||||
|
auto opt_nozzle_volume_type = dynamic_cast<const ConfigOptionEnumsGeneric*>(this->project_config.option("nozzle_volume_type"));
|
||||||
|
for (int index = 0; index < filament_count; index++)
|
||||||
|
{
|
||||||
|
if (opt_nozzle_volume_type && opt_nozzle_volume_type->values.size() > (f_maps[index] - 1))
|
||||||
|
result[index] = opt_nozzle_volume_type->values[f_maps[index] - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicPrintConfig PresetBundle::full_config(bool apply_extruder, std::optional<std::vector<int>>filament_maps, std::optional<std::vector<int>> filament_volume_maps) const
|
||||||
{
|
{
|
||||||
return (this->printers.get_edited_preset().printer_technology() == ptFFF) ?
|
return (this->printers.get_edited_preset().printer_technology() == ptFFF) ?
|
||||||
this->full_fff_config(apply_extruder, filament_maps) :
|
this->full_fff_config(apply_extruder, filament_maps, filament_volume_maps) :
|
||||||
this->full_sla_config();
|
this->full_sla_config();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3944,7 +3993,7 @@ const std::set<std::string> ignore_settings_list ={
|
|||||||
"print_settings_id", "filament_settings_id", "printer_settings_id"
|
"print_settings_id", "filament_settings_id", "printer_settings_id"
|
||||||
};
|
};
|
||||||
|
|
||||||
DynamicPrintConfig PresetBundle::full_fff_config(bool apply_extruder, std::optional<std::vector<int>> filament_maps_new) const
|
DynamicPrintConfig PresetBundle::full_fff_config(bool apply_extruder, std::optional<std::vector<int>> filament_maps_new, std::optional<std::vector<int>> filament_volume_maps_new) const
|
||||||
{
|
{
|
||||||
DynamicPrintConfig out;
|
DynamicPrintConfig out;
|
||||||
out.apply(FullPrintConfig::defaults());
|
out.apply(FullPrintConfig::defaults());
|
||||||
@@ -3958,8 +4007,17 @@ DynamicPrintConfig PresetBundle::full_fff_config(bool apply_extruder, std::optio
|
|||||||
size_t num_filaments = this->filament_presets.size();
|
size_t num_filaments = this->filament_presets.size();
|
||||||
|
|
||||||
std::vector<int> filament_maps = out.option<ConfigOptionInts>("filament_map")->values;
|
std::vector<int> filament_maps = out.option<ConfigOptionInts>("filament_map")->values;
|
||||||
|
std::vector<int> filament_volume_maps(num_filaments, (int)nvtStandard);
|
||||||
|
|
||||||
|
ConfigOptionInts* filament_volume_map_opt = out.option<ConfigOptionInts>("filament_volume_map");
|
||||||
if (filament_maps_new.has_value())
|
if (filament_maps_new.has_value())
|
||||||
filament_maps = *filament_maps_new;
|
filament_maps = *filament_maps_new;
|
||||||
|
if (filament_volume_maps_new.has_value()) {
|
||||||
|
filament_volume_maps = *filament_volume_maps_new;
|
||||||
|
out.option<ConfigOptionInts>("filament_volume_map", true)->values = filament_volume_maps;
|
||||||
|
}
|
||||||
|
else if (filament_volume_map_opt && filament_volume_map_opt->values.size() == num_filaments)
|
||||||
|
filament_volume_maps = filament_volume_map_opt->values;
|
||||||
//in some middle state, they may be different
|
//in some middle state, they may be different
|
||||||
if (filament_maps.size() != num_filaments) {
|
if (filament_maps.size() != num_filaments) {
|
||||||
filament_maps.resize(num_filaments, 1);
|
filament_maps.resize(num_filaments, 1);
|
||||||
@@ -3967,6 +4025,9 @@ DynamicPrintConfig PresetBundle::full_fff_config(bool apply_extruder, std::optio
|
|||||||
else {
|
else {
|
||||||
assert(filament_maps.size() == num_filaments);
|
assert(filament_maps.size() == num_filaments);
|
||||||
}
|
}
|
||||||
|
if (filament_volume_maps.size() != num_filaments) {
|
||||||
|
filament_volume_maps.resize(num_filaments, nvtStandard);
|
||||||
|
}
|
||||||
|
|
||||||
auto* extruder_diameter = dynamic_cast<const ConfigOptionFloats*>(out.option("nozzle_diameter"));
|
auto* extruder_diameter = dynamic_cast<const ConfigOptionFloats*>(out.option("nozzle_diameter"));
|
||||||
// Collect the "compatible_printers_condition" and "inherits" values over all presets (print, filaments, printers) into a single vector.
|
// Collect the "compatible_printers_condition" and "inherits" values over all presets (print, filaments, printers) into a single vector.
|
||||||
@@ -4023,7 +4084,7 @@ DynamicPrintConfig PresetBundle::full_fff_config(bool apply_extruder, std::optio
|
|||||||
//BBS: update filament config related with variants
|
//BBS: update filament config related with variants
|
||||||
DynamicPrintConfig filament_config = this->filaments.get_edited_preset().config;
|
DynamicPrintConfig filament_config = this->filaments.get_edited_preset().config;
|
||||||
if (apply_extruder && ((extruder_count > 1) || different_extruder))
|
if (apply_extruder && ((extruder_count > 1) || different_extruder))
|
||||||
filament_config.update_values_to_printer_extruders(out, extruder_count, extruder_volume_type_count, nozzle_volume_types, filament_options_with_variant, "", "filament_extruder_variant", 1, filament_maps[0]);
|
filament_config.update_values_to_printer_extruders(out, extruder_count, extruder_volume_type_count, nozzle_volume_types, filament_options_with_variant, "", "filament_extruder_variant", 1, filament_maps[0], (NozzleVolumeType)filament_volume_maps[0]);
|
||||||
out.apply(filament_config);
|
out.apply(filament_config);
|
||||||
compatible_printers_condition.emplace_back(this->filaments.get_edited_preset().compatible_printers_condition());
|
compatible_printers_condition.emplace_back(this->filaments.get_edited_preset().compatible_printers_condition());
|
||||||
compatible_prints_condition .emplace_back(this->filaments.get_edited_preset().compatible_prints_condition());
|
compatible_prints_condition .emplace_back(this->filaments.get_edited_preset().compatible_prints_condition());
|
||||||
@@ -4117,7 +4178,7 @@ DynamicPrintConfig PresetBundle::full_fff_config(bool apply_extruder, std::optio
|
|||||||
for (size_t i = 0; i < num_filaments; ++i) {
|
for (size_t i = 0; i < num_filaments; ++i) {
|
||||||
filament_temp_configs[i] = *(filament_configs[i]);
|
filament_temp_configs[i] = *(filament_configs[i]);
|
||||||
if (apply_extruder && ((extruder_count > 1) || different_extruder))
|
if (apply_extruder && ((extruder_count > 1) || different_extruder))
|
||||||
filament_temp_configs[i].update_values_to_printer_extruders(out, extruder_count, extruder_volume_type_count, nozzle_volume_types, filament_options_with_variant, "", "filament_extruder_variant", 1, filament_maps[i]);
|
filament_temp_configs[i].update_values_to_printer_extruders(out, extruder_count, extruder_volume_type_count, nozzle_volume_types, filament_options_with_variant, "", "filament_extruder_variant", 1, filament_maps[i], (NozzleVolumeType)filament_volume_maps[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// loop through options and apply them to the resulting config.
|
// loop through options and apply them to the resulting config.
|
||||||
|
|||||||
@@ -175,7 +175,8 @@ public:
|
|||||||
const DynamicPrintConfig &project_config,
|
const DynamicPrintConfig &project_config,
|
||||||
std::vector<Preset> &in_filament_presets,
|
std::vector<Preset> &in_filament_presets,
|
||||||
bool apply_extruder,
|
bool apply_extruder,
|
||||||
std::optional<std::vector<int>> filament_maps_new);
|
std::optional<std::vector<int>> filament_maps_new,
|
||||||
|
std::optional<std::vector<int>> filament_volume_maps_new = std::nullopt);
|
||||||
|
|
||||||
// ORCA: utility function to find the vendor for a given preset name
|
// ORCA: utility function to find the vendor for a given preset name
|
||||||
static std::string find_preset_vendor(const std::string& preset_name, Preset::Type type);
|
static std::string find_preset_vendor(const std::string& preset_name, Preset::Type type);
|
||||||
@@ -383,10 +384,14 @@ public:
|
|||||||
bool has_defauls_only() const
|
bool has_defauls_only() const
|
||||||
{ return prints.has_defaults_only() && filaments.has_defaults_only() && printers.has_defaults_only(); }
|
{ return prints.has_defaults_only() && filaments.has_defaults_only() && printers.has_defaults_only(); }
|
||||||
|
|
||||||
DynamicPrintConfig full_config(bool apply_extruder = true, std::optional<std::vector<int>>filament_maps = std::nullopt) const;
|
DynamicPrintConfig full_config(bool apply_extruder = true, std::optional<std::vector<int>>filament_maps = std::nullopt, std::optional<std::vector<int>> filament_volume_maps = std::nullopt) const;
|
||||||
// full_config() with the some "useless" config removed.
|
// full_config() with the some "useless" config removed.
|
||||||
DynamicPrintConfig full_config_secure(std::optional<std::vector<int>>filament_maps = std::nullopt) const;
|
DynamicPrintConfig full_config_secure(std::optional<std::vector<int>>filament_maps = std::nullopt) const;
|
||||||
|
|
||||||
|
// Default per-filament nozzle-volume types: each filament inherits the volume type of the
|
||||||
|
// extruder it maps to (1-based f_maps), Standard when unknown.
|
||||||
|
std::vector<int> get_default_nozzle_volume_types_for_filaments(std::vector<int>& f_maps);
|
||||||
|
|
||||||
// Per-extruder flush matrix [extruder_id][from_filament][to_filament] in mm^3, optionally scaled
|
// Per-extruder flush matrix [extruder_id][from_filament][to_filament] in mm^3, optionally scaled
|
||||||
// by the per-extruder flush_multiplier (or flush_multiplier_fast when prime_volume_mode==Fast).
|
// by the per-extruder flush_multiplier (or flush_multiplier_fast when prime_volume_mode==Fast).
|
||||||
// Used by the print-dispatch nozzle-mapping flush-weight estimate.
|
// Used by the print-dispatch nozzle-mapping flush-weight estimate.
|
||||||
@@ -543,7 +548,7 @@ private:
|
|||||||
/*ConfigSubstitutions load_config_file_config_bundle(
|
/*ConfigSubstitutions load_config_file_config_bundle(
|
||||||
const std::string &path, const boost::property_tree::ptree &tree, ForwardCompatibilitySubstitutionRule compatibility_rule);*/
|
const std::string &path, const boost::property_tree::ptree &tree, ForwardCompatibilitySubstitutionRule compatibility_rule);*/
|
||||||
|
|
||||||
DynamicPrintConfig full_fff_config(bool apply_extruder, std::optional<std::vector<int>> filament_maps=std::nullopt) const;
|
DynamicPrintConfig full_fff_config(bool apply_extruder, std::optional<std::vector<int>> filament_maps=std::nullopt, std::optional<std::vector<int>> filament_volume_maps=std::nullopt) const;
|
||||||
DynamicPrintConfig full_sla_config() const;
|
DynamicPrintConfig full_sla_config() const;
|
||||||
|
|
||||||
// Orca: used for validation only
|
// Orca: used for validation only
|
||||||
|
|||||||
+59
-8
@@ -334,8 +334,11 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
|
|||||||
|| opt_key == "other_layers_print_sequence_nums"
|
|| opt_key == "other_layers_print_sequence_nums"
|
||||||
|| opt_key == "toolchange_ordering"
|
|| opt_key == "toolchange_ordering"
|
||||||
|| opt_key == "extruder_ams_count"
|
|| opt_key == "extruder_ams_count"
|
||||||
|
|| opt_key == "extruder_nozzle_stats"
|
||||||
|| opt_key == "filament_map_mode"
|
|| opt_key == "filament_map_mode"
|
||||||
|| opt_key == "filament_map"
|
|| opt_key == "filament_map"
|
||||||
|
|| opt_key == "filament_nozzle_map"
|
||||||
|
|| opt_key == "filament_volume_map"
|
||||||
|| opt_key == "filament_adhesiveness_category"
|
|| opt_key == "filament_adhesiveness_category"
|
||||||
|| opt_key == "filament_tower_interface_pre_extrusion_dist"
|
|| opt_key == "filament_tower_interface_pre_extrusion_dist"
|
||||||
|| opt_key == "filament_tower_interface_pre_extrusion_length"
|
|| opt_key == "filament_tower_interface_pre_extrusion_length"
|
||||||
@@ -2509,6 +2512,10 @@ void Print::process(long long *time_cost_with_cache, bool use_cache)
|
|||||||
std::vector<int>filament_maps = this->get_filament_maps();
|
std::vector<int>filament_maps = this->get_filament_maps();
|
||||||
auto map_mode = get_filament_map_mode();
|
auto map_mode = get_filament_map_mode();
|
||||||
// get recommended filament map
|
// get recommended filament map
|
||||||
|
// Orca: the sequential write-back stays gated to auto modes. In manual modes the
|
||||||
|
// config maps already carry the user's assignment (the per-object ToolOrdering below
|
||||||
|
// consumes them directly), so a write-back would only re-store the pre-slice values;
|
||||||
|
// keeping the gate avoids churning the config on every sequential manual slice.
|
||||||
if (map_mode < FilamentMapMode::fmmManual) {
|
if (map_mode < FilamentMapMode::fmmManual) {
|
||||||
// Grouping returns a nozzle-aware result; the 1-based extruder map
|
// Grouping returns a nozzle-aware result; the 1-based extruder map
|
||||||
// for the by-object path is derived from it.
|
// for the by-object path is derived from it.
|
||||||
@@ -2516,7 +2523,25 @@ void Print::process(long long *time_cost_with_cache, bool use_cache)
|
|||||||
auto derived_maps = grouping_result.get_extruder_map(false);
|
auto derived_maps = grouping_result.get_extruder_map(false);
|
||||||
if (!derived_maps.empty()) {
|
if (!derived_maps.empty()) {
|
||||||
filament_maps = derived_maps;
|
filament_maps = derived_maps;
|
||||||
update_filament_maps_to_config(filament_maps);
|
// Write the maps back: used filaments adopt the engine's extruder/nozzle
|
||||||
|
// choice, unused ones keep their config assignment.
|
||||||
|
// Orca: the config maps are the merge base; fall back to a synthesized base
|
||||||
|
// when no producer sized them to the filament count (CLI runs until the
|
||||||
|
// per-filament synthesis lands there), where indexing per filament would
|
||||||
|
// run out of bounds.
|
||||||
|
std::vector<int> base_filament_map = m_config.filament_map.values;
|
||||||
|
if (base_filament_map.size() != derived_maps.size())
|
||||||
|
base_filament_map.assign(derived_maps.size(), 1);
|
||||||
|
std::vector<int> base_volume_map = m_config.filament_volume_map.values;
|
||||||
|
if (base_volume_map.size() != derived_maps.size())
|
||||||
|
base_volume_map.assign(derived_maps.size(), (int)nvtStandard);
|
||||||
|
// Orca: as on the non-sequential path, the engine's concrete volume
|
||||||
|
// assignment (get_volume_map()) is deliberately not merged in until the
|
||||||
|
// layer-aware g-code resolvers consume it; the config keeps its own
|
||||||
|
// (GUI-injected or project) volume map, size-corrected above.
|
||||||
|
update_filament_maps_to_config(FilamentGroupUtils::update_used_filament_values(base_filament_map, derived_maps, used_filaments),
|
||||||
|
base_volume_map,
|
||||||
|
grouping_result.get_nozzle_map());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// check map valid both in auto and mannual mode
|
// check map valid both in auto and mannual mode
|
||||||
@@ -3198,14 +3223,30 @@ void Print::finalize_first_layer_convex_hull()
|
|||||||
m_first_layer_convex_hull = Geometry::convex_hull(m_first_layer_convex_hull.points);
|
m_first_layer_convex_hull = Geometry::convex_hull(m_first_layer_convex_hull.points);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Print::update_filament_maps_to_config(std::vector<int> f_maps)
|
void Print::update_filament_maps_to_config(std::vector<int> f_maps, std::vector<int> f_volume_maps, std::vector<int> f_nozzle_maps)
|
||||||
{
|
{
|
||||||
if (m_config.filament_map.values != f_maps)
|
if ((m_config.filament_map.values != f_maps) || (m_config.filament_volume_map.values != f_volume_maps) || (m_config.filament_nozzle_map.values != f_nozzle_maps))
|
||||||
{
|
{
|
||||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": filament maps changed after pre-slicing.");
|
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": filament maps changed after pre-slicing.");
|
||||||
m_ori_full_print_config.option<ConfigOptionInts>("filament_map", true)->values = f_maps;
|
m_ori_full_print_config.option<ConfigOptionInts>("filament_map", true)->values = f_maps;
|
||||||
m_config.filament_map.values = f_maps;
|
m_config.filament_map.values = f_maps;
|
||||||
|
|
||||||
|
if (!f_volume_maps.empty()) {
|
||||||
|
m_ori_full_print_config.option<ConfigOptionInts>("filament_volume_map", true)->values = f_volume_maps;
|
||||||
|
m_config.filament_volume_map.values = f_volume_maps;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_ori_full_print_config.option<ConfigOptionInts>("filament_volume_map", true)->values.resize(f_maps.size(), nvtStandard);
|
||||||
|
m_config.filament_volume_map.values.resize(f_maps.size(), nvtStandard);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!f_nozzle_maps.empty()) {
|
||||||
|
m_ori_full_print_config.option<ConfigOptionInts>("filament_nozzle_map", true)->values = f_nozzle_maps;
|
||||||
|
m_config.filament_nozzle_map.values = f_nozzle_maps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
int extruder_count = 1, extruder_volume_type_count = 1;
|
int extruder_count = 1, extruder_volume_type_count = 1;
|
||||||
bool support_multi = m_ori_full_print_config.support_different_extruders(extruder_count);
|
bool support_multi = m_ori_full_print_config.support_different_extruders(extruder_count);
|
||||||
std::vector<std::vector<NozzleVolumeType>> nozzle_volume_types;
|
std::vector<std::vector<NozzleVolumeType>> nozzle_volume_types;
|
||||||
@@ -3221,15 +3262,22 @@ void Print::update_filament_maps_to_config(std::vector<int> f_maps)
|
|||||||
auto opt_extruder_type = dynamic_cast<const ConfigOptionEnumsGeneric*>(m_ori_full_print_config.option("extruder_type"));
|
auto opt_extruder_type = dynamic_cast<const ConfigOptionEnumsGeneric*>(m_ori_full_print_config.option("extruder_type"));
|
||||||
auto opt_nozzle_volume_type = dynamic_cast<const ConfigOptionEnumsGeneric*>(m_ori_full_print_config.option("nozzle_volume_type"));
|
auto opt_nozzle_volume_type = dynamic_cast<const ConfigOptionEnumsGeneric*>(m_ori_full_print_config.option("nozzle_volume_type"));
|
||||||
// Orca: the loop tolerates configs without the extruder options (unit tests, degenerate
|
// Orca: the loop tolerates configs without the extruder options (unit tests, degenerate
|
||||||
// presets); the volume-map override keeps the sizing guard used everywhere else, and the
|
// presets); the backfill and the override are bounds-checked because the change block above
|
||||||
// grouping engine does not produce per-filament volume maps yet, so m_config only carries
|
// is skipped when the maps are unchanged, in which case the stored map may be shorter than
|
||||||
// a map when the project supplied one.
|
// the filament count.
|
||||||
|
auto* ori_volume_map = m_ori_full_print_config.option<ConfigOptionInts>("filament_volume_map", true);
|
||||||
for (int index = 0; opt_extruder_type && opt_nozzle_volume_type && index < f_maps.size(); index++)
|
for (int index = 0; opt_extruder_type && opt_nozzle_volume_type && index < f_maps.size(); index++)
|
||||||
{
|
{
|
||||||
ExtruderType extruder_type = (ExtruderType)(opt_extruder_type->get_at(f_maps[index] - 1));
|
ExtruderType extruder_type = (ExtruderType)(opt_extruder_type->get_at(f_maps[index] - 1));
|
||||||
NozzleVolumeType nozzle_volume_type = (NozzleVolumeType)(opt_nozzle_volume_type->get_at(f_maps[index] - 1));
|
NozzleVolumeType nozzle_volume_type = (NozzleVolumeType)(opt_nozzle_volume_type->get_at(f_maps[index] - 1));
|
||||||
if ((extruder_volume_type_count > extruder_count)
|
if (f_volume_maps.empty()) {
|
||||||
&& f_maps.size() > 1 && m_config.filament_volume_map.values.size() == f_maps.size())
|
// No per-filament map supplied: backfill from the extruder's own volume type.
|
||||||
|
if (m_config.filament_volume_map.values.size() > index)
|
||||||
|
m_config.filament_volume_map.values[index] = nozzle_volume_type;
|
||||||
|
if (ori_volume_map->values.size() > index)
|
||||||
|
ori_volume_map->values[index] = nozzle_volume_type;
|
||||||
|
}
|
||||||
|
else if ((extruder_volume_type_count > extruder_count) && (m_config.filament_volume_map.values.size() > index))
|
||||||
nozzle_volume_type = (NozzleVolumeType)(m_config.filament_volume_map.values[index]);
|
nozzle_volume_type = (NozzleVolumeType)(m_config.filament_volume_map.values[index]);
|
||||||
m_config.filament_map_2.values[index] = m_ori_full_print_config.get_index_for_extruder(f_maps[index], "print_extruder_id", extruder_type, nozzle_volume_type, "print_extruder_variant");
|
m_config.filament_map_2.values[index] = m_ori_full_print_config.get_index_for_extruder(f_maps[index], "print_extruder_id", extruder_type, nozzle_volume_type, "print_extruder_variant");
|
||||||
}
|
}
|
||||||
@@ -3254,8 +3302,11 @@ void Print::update_filament_maps_to_config(std::vector<int> f_maps)
|
|||||||
compute_filament_override_value(opt_key, opt_old_machine, opt_new_machine, opt_new_filament, m_full_print_config, print_diff, filament_overrides, m_config.filament_map_2.values);
|
compute_filament_override_value(opt_key, opt_old_machine, opt_new_machine, opt_new_filament, m_full_print_config, print_diff, filament_overrides, m_config.filament_map_2.values);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((extruder_count > 1) || support_multi) {
|
||||||
t_config_option_keys keys(filament_options_with_variant.begin(), filament_options_with_variant.end());
|
t_config_option_keys keys(filament_options_with_variant.begin(), filament_options_with_variant.end());
|
||||||
|
keys.push_back("filament_self_index");
|
||||||
m_config.apply_only(m_full_print_config, keys, true);
|
m_config.apply_only(m_full_print_config, keys, true);
|
||||||
|
}
|
||||||
if (!print_diff.empty()) {
|
if (!print_diff.empty()) {
|
||||||
m_placeholder_parser.apply_config(filament_overrides);
|
m_placeholder_parser.apply_config(filament_overrides);
|
||||||
m_config.apply(filament_overrides);
|
m_config.apply(filament_overrides);
|
||||||
|
|||||||
@@ -1005,7 +1005,7 @@ public:
|
|||||||
const WipeTowerData& wipe_tower_data(size_t filaments_cnt = 0) const;
|
const WipeTowerData& wipe_tower_data(size_t filaments_cnt = 0) const;
|
||||||
const ToolOrdering& tool_ordering() const { return m_tool_ordering; }
|
const ToolOrdering& tool_ordering() const { return m_tool_ordering; }
|
||||||
|
|
||||||
void update_filament_maps_to_config(std::vector<int> f_maps);
|
void update_filament_maps_to_config(std::vector<int> f_maps, std::vector<int> f_volume_maps = std::vector<int>{}, std::vector<int> f_nozzle_maps = std::vector<int>{});
|
||||||
void apply_config_for_render(const DynamicConfig &config);
|
void apply_config_for_render(const DynamicConfig &config);
|
||||||
|
|
||||||
// 1 based group ids
|
// 1 based group ids
|
||||||
|
|||||||
@@ -1212,7 +1212,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
|||||||
|
|
||||||
//BBS: process the filament_map related logic
|
//BBS: process the filament_map related logic
|
||||||
std::unordered_set<std::string> print_diff_set(print_diff.begin(), print_diff.end());
|
std::unordered_set<std::string> print_diff_set(print_diff.begin(), print_diff.end());
|
||||||
if (print_diff_set.find("filament_map_mode") == print_diff_set.end())
|
if (!print_diff_set.empty() && print_diff_set.find("filament_map_mode") == print_diff_set.end())
|
||||||
{
|
{
|
||||||
FilamentMapMode map_mode = new_full_config.option<ConfigOptionEnum<FilamentMapMode>>("filament_map_mode", true)->value;
|
FilamentMapMode map_mode = new_full_config.option<ConfigOptionEnum<FilamentMapMode>>("filament_map_mode", true)->value;
|
||||||
if (is_auto_filament_map_mode(map_mode)) {
|
if (is_auto_filament_map_mode(map_mode)) {
|
||||||
@@ -1224,9 +1224,29 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
|||||||
old_opt->set(new_opt);
|
old_opt->set(new_opt);
|
||||||
m_config.filament_map = *new_opt;
|
m_config.filament_map = *new_opt;
|
||||||
}
|
}
|
||||||
|
if (print_diff_set.find("filament_volume_map") != print_diff_set.end()) {
|
||||||
|
print_diff_set.erase("filament_volume_map");
|
||||||
|
//full_config_diff.erase("filament_volume_map");
|
||||||
|
ConfigOptionInts* old_opt = m_full_print_config.option<ConfigOptionInts>("filament_volume_map", true);
|
||||||
|
ConfigOptionInts* new_opt = new_full_config.option<ConfigOptionInts>("filament_volume_map", true);
|
||||||
|
old_opt->set(new_opt);
|
||||||
|
m_config.filament_volume_map = *new_opt;
|
||||||
|
}
|
||||||
|
if (print_diff_set.find("filament_nozzle_map") != print_diff_set.end()) {
|
||||||
|
print_diff_set.erase("filament_nozzle_map");
|
||||||
|
//full_config_diff.erase("filament_nozzle_map");
|
||||||
|
ConfigOptionInts* old_opt = m_full_print_config.option<ConfigOptionInts>("filament_nozzle_map", true);
|
||||||
|
ConfigOptionInts* new_opt = new_full_config.option<ConfigOptionInts>("filament_nozzle_map", true);
|
||||||
|
old_opt->set(new_opt);
|
||||||
|
m_config.filament_nozzle_map = *new_opt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
print_diff_set.erase("extruder_ams_count");
|
print_diff_set.erase("extruder_ams_count");
|
||||||
|
if (map_mode == fmmManual) {
|
||||||
|
// filament_nozzle_map is an engine output, not a GUI input, in manual mode
|
||||||
|
print_diff_set.erase("filament_nozzle_map");
|
||||||
|
}
|
||||||
std::vector<int> old_filament_map = m_config.filament_map.values;
|
std::vector<int> old_filament_map = m_config.filament_map.values;
|
||||||
std::vector<int> new_filament_map = new_full_config.option<ConfigOptionInts>("filament_map", true)->values;
|
std::vector<int> new_filament_map = new_full_config.option<ConfigOptionInts>("filament_map", true)->values;
|
||||||
|
|
||||||
@@ -1243,8 +1263,32 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (same_map)
|
if (same_map) {
|
||||||
print_diff_set.erase("filament_map");
|
print_diff_set.erase("filament_map");
|
||||||
|
|
||||||
|
// The extruder retract overrides are keyed by the (unchanged) filament map;
|
||||||
|
// recompute them and drop diffs whose recomputed value matches the current
|
||||||
|
// config, so a cosmetic reordering of unused filaments does not invalidate.
|
||||||
|
const auto& retract_keys = print_config_def.extruder_retract_keys();
|
||||||
|
const std::string filament_prefix = "filament_";
|
||||||
|
std::vector<int> old_f_map_indices(old_filament_map.size(), 0);
|
||||||
|
for (size_t i = 0; i < old_filament_map.size(); i++)
|
||||||
|
old_f_map_indices[i] = old_filament_map[i] - 1;
|
||||||
|
|
||||||
|
for (const auto& rk : retract_keys) {
|
||||||
|
if (print_diff_set.find(rk) == print_diff_set.end())
|
||||||
|
continue;
|
||||||
|
const ConfigOption* opt_old = m_config.option(rk);
|
||||||
|
const ConfigOption* opt_new_m = new_full_config.option(rk);
|
||||||
|
const ConfigOption* opt_new_f = new_full_config.option(filament_prefix + rk);
|
||||||
|
if (opt_old && opt_new_m && opt_new_f) {
|
||||||
|
std::unique_ptr<ConfigOption> opt_recomputed(opt_new_m->clone());
|
||||||
|
opt_recomputed->apply_override(opt_new_f, old_f_map_indices);
|
||||||
|
if (*opt_old == *opt_recomputed)
|
||||||
|
print_diff_set.erase(rk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (print_diff_set.size() != print_diff.size())
|
if (print_diff_set.size() != print_diff.size())
|
||||||
@@ -1265,11 +1309,12 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
|||||||
{
|
{
|
||||||
ExtruderType extruder_type = (ExtruderType)(opt_extruder_type->get_at(filament_maps[index] - 1));
|
ExtruderType extruder_type = (ExtruderType)(opt_extruder_type->get_at(filament_maps[index] - 1));
|
||||||
NozzleVolumeType nozzle_volume_type = (NozzleVolumeType)(opt_nozzle_volume_type->get_at(filament_maps[index] - 1));
|
NozzleVolumeType nozzle_volume_type = (NozzleVolumeType)(opt_nozzle_volume_type->get_at(filament_maps[index] - 1));
|
||||||
// Orca: the per-filament volume map is only trustworthy when a producer explicitly sized it
|
// Orca: honour the per-filament volume map only when a producer sized it to the filament
|
||||||
// to the filament count; the registered default is a 1-element vector (see
|
// count; mis-sized maps (stale project values, CLI runs until the per-filament synthesis
|
||||||
|
// lands there) must not be indexed per filament (see
|
||||||
// update_values_to_printer_extruders_for_multiple_filaments for the same guard).
|
// update_values_to_printer_extruders_for_multiple_filaments for the same guard).
|
||||||
if ((extruder_volume_type_count > extruder_count) && opt_filament_volume_maps
|
if ((extruder_volume_type_count > extruder_count) && opt_filament_volume_maps
|
||||||
&& filament_maps.size() > 1 && opt_filament_volume_maps->values.size() == filament_maps.size())
|
&& opt_filament_volume_maps->values.size() == filament_maps.size())
|
||||||
nozzle_volume_type = (NozzleVolumeType)(opt_filament_volume_maps->values[index]);
|
nozzle_volume_type = (NozzleVolumeType)(opt_filament_volume_maps->values[index]);
|
||||||
m_config.filament_map_2.values[index] = new_full_config.get_index_for_extruder(filament_maps[index], "print_extruder_id", extruder_type, nozzle_volume_type, "print_extruder_variant");
|
m_config.filament_map_2.values[index] = new_full_config.get_index_for_extruder(filament_maps[index], "print_extruder_id", extruder_type, nozzle_volume_type, "print_extruder_variant");
|
||||||
}
|
}
|
||||||
@@ -1694,6 +1739,12 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
|||||||
m_default_object_config.apply_only(new_full_config, new_changed_keys, true);
|
m_default_object_config.apply_only(new_full_config, new_changed_keys, true);
|
||||||
// Handle changes to regions config defaults
|
// Handle changes to regions config defaults
|
||||||
m_default_region_config.apply_only(new_full_config, new_changed_keys, true);
|
m_default_region_config.apply_only(new_full_config, new_changed_keys, true);
|
||||||
|
// Orca: keep the pre-expansion snapshot in sync with this late normalization pass.
|
||||||
|
// The engine map write-back rebuilds m_full_print_config from m_ori_full_print_config
|
||||||
|
// after slicing; a stale snapshot would resurrect the un-normalized values (e.g.
|
||||||
|
// enable_prime_tower on a single-filament print) in the dumped config and spuriously
|
||||||
|
// re-invalidate the g-code on the next apply.
|
||||||
|
m_ori_full_print_config.apply_only(new_full_config, new_changed_keys, true);
|
||||||
m_full_print_config = std::move(new_full_config);
|
m_full_print_config = std::move(new_full_config);
|
||||||
update_filament_self_index_cache();
|
update_filament_self_index_cache();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2743,8 +2743,10 @@ void PrintConfigDef::init_fff_params()
|
|||||||
|
|
||||||
// Per-filament nozzle-volume-type override (multi-volume/Hybrid). Round-trips through .3mf
|
// Per-filament nozzle-volume-type override (multi-volume/Hybrid). Round-trips through .3mf
|
||||||
// plate metadata (filament_volume_maps) and steers per-filament slot resolution when an
|
// plate metadata (filament_volume_maps) and steers per-filament slot resolution when an
|
||||||
// extruder exposes several volume types; inert for existing printers (no producer sizes it
|
// extruder exposes several volume types. Producers: the GUI full-config composition injects
|
||||||
// to the filament count until the write-back pipeline lands).
|
// a filament-count-sized map (plate map, else per-extruder defaults) and the project config
|
||||||
|
// keeps it sized; expansion trusts the map only when its size matches the filament count
|
||||||
|
// (CLI runs may still carry the 1-element default).
|
||||||
def = this->add("filament_volume_map", coInts);
|
def = this->add("filament_volume_map", coInts);
|
||||||
def->mode = comDevelop;
|
def->mode = comDevelop;
|
||||||
def->set_default_value(new ConfigOptionInts{(int)(NozzleVolumeType::nvtStandard)});
|
def->set_default_value(new ConfigOptionInts{(int)(NozzleVolumeType::nvtStandard)});
|
||||||
@@ -2774,8 +2776,10 @@ void PrintConfigDef::init_fff_params()
|
|||||||
def->mode = comAdvanced;
|
def->mode = comAdvanced;
|
||||||
def->set_default_value(new ConfigOptionEnum<FilamentMapMode>(fmmAutoForFlush));
|
def->set_default_value(new ConfigOptionEnum<FilamentMapMode>(fmmAutoForFlush));
|
||||||
|
|
||||||
// Fully-manual mode (fmmNozzleManual): per-filament -> physical-nozzle assignment.
|
// Per-filament -> physical-nozzle assignment. Written back by the grouping engine after
|
||||||
// Inert until the nozzle-assignment engine consumes it. Internal use only, no translation.
|
// slicing (all non-sequential modes) and read back to the plate config; a user input only
|
||||||
|
// in fully-manual mode (fmmNozzleManual). Dumped in the g-code header for diagnostics.
|
||||||
|
// Internal use only, no translation.
|
||||||
def = this->add("filament_nozzle_map", coInts);
|
def = this->add("filament_nozzle_map", coInts);
|
||||||
def->mode = comDevelop;
|
def->mode = comDevelop;
|
||||||
def->set_default_value(new ConfigOptionInts{1});
|
def->set_default_value(new ConfigOptionInts{1});
|
||||||
@@ -10533,12 +10537,12 @@ void DynamicPrintConfig::update_values_to_printer_extruders_for_multiple_filamen
|
|||||||
|
|
||||||
auto opt_filament_volume_maps = dynamic_cast<const ConfigOptionInts*>(printer_config.option("filament_volume_map"));
|
auto opt_filament_volume_maps = dynamic_cast<const ConfigOptionInts*>(printer_config.option("filament_volume_map"));
|
||||||
std::vector<int> filament_volume_maps;
|
std::vector<int> filament_volume_maps;
|
||||||
// Orca: the per-filament volume map is only trustworthy when a producer explicitly
|
// Orca: honour the per-filament volume map only when a producer sized it to the
|
||||||
// sized it to the filament count; the registered default is a 1-element vector and
|
// filament count. The full-config producers (PresetBundle injection, engine
|
||||||
// stale project values may be mis-sized. A single-filament config cannot be told
|
// write-back) always size it; mis-sized maps (stale project values, CLI runs until
|
||||||
// apart from that default by size, so it is ignored too until the pipeline that
|
// the per-filament synthesis lands there) must not distort slot resolution nor be
|
||||||
// seeds the map lands; anything untrusted must not distort slot resolution.
|
// indexed out of bounds.
|
||||||
if (opt_filament_volume_maps && filament_count > 1 && opt_filament_volume_maps->values.size() == filament_count)
|
if (opt_filament_volume_maps && opt_filament_volume_maps->values.size() == filament_count)
|
||||||
filament_volume_maps = opt_filament_volume_maps->values;
|
filament_volume_maps = opt_filament_volume_maps->values;
|
||||||
auto opt_ids = id_name.empty()? nullptr: dynamic_cast<const ConfigOptionInts*>(this->option(id_name));
|
auto opt_ids = id_name.empty()? nullptr: dynamic_cast<const ConfigOptionInts*>(this->option(id_name));
|
||||||
std::vector<int> variant_index;
|
std::vector<int> variant_index;
|
||||||
|
|||||||
@@ -231,6 +231,19 @@ void BackgroundSlicingProcess::process_fff()
|
|||||||
if (m_current_plate->get_real_filament_map_mode(preset_bundle.project_config) < FilamentMapMode::fmmManual) {
|
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();
|
std::vector<int> f_maps = m_fff_print->get_filament_maps();
|
||||||
m_current_plate->set_filament_maps(f_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);
|
wxCommandEvent evt(m_event_slicing_completed_id);
|
||||||
// Post the Slicing Finished message for the G-code viewer to update.
|
// Post the Slicing Finished message for the G-code viewer to update.
|
||||||
|
|||||||
@@ -319,6 +319,18 @@ std::vector<int> PartPlate::get_real_filament_maps(const DynamicConfig& g_config
|
|||||||
return g_maps;
|
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
|
FilamentMapMode PartPlate::get_real_filament_map_mode(const DynamicConfig& g_config, bool* use_global_param) const
|
||||||
{
|
{
|
||||||
auto mode = get_filament_map_mode();
|
auto mode = get_filament_map_mode();
|
||||||
@@ -3506,8 +3518,16 @@ int PartPlate::load_gcode_from_file(const std::string& filename)
|
|||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
// process gcode
|
// process gcode
|
||||||
|
auto& preset_bundle = wxGetApp().preset_bundle;
|
||||||
std::vector<int> filament_maps = this->get_filament_maps();
|
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);
|
full_config.apply(m_config, true);
|
||||||
m_print->apply(*m_model, full_config, false);
|
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,
|
//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");
|
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()
|
void PartPlate::clear_filament_map_mode()
|
||||||
{
|
{
|
||||||
if (m_config.has("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);
|
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);
|
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;
|
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 w = dynamic_cast<const ConfigOptionFloat *>(print_cfg.option("prime_tower_width"))->value;
|
||||||
float v = dynamic_cast<const ConfigOptionFloat *>(full_config.option("prime_volume"))->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;
|
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_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_real_filament_map_mode(const DynamicConfig& g_config,bool * use_global_param = nullptr) const;
|
||||||
|
|
||||||
FilamentMapMode get_filament_map_mode() const;
|
FilamentMapMode get_filament_map_mode() const;
|
||||||
@@ -262,6 +263,15 @@ public:
|
|||||||
std::vector<int> get_filament_maps() const;
|
std::vector<int> get_filament_maps() const;
|
||||||
void set_filament_maps(const std::vector<int>& f_maps);
|
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();
|
||||||
void clear_filament_map_mode();
|
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) {
|
if (preset_bundle->get_printer_extruder_count() > 1) {
|
||||||
PartPlate* cur_plate = background_process.get_current_plate();
|
PartPlate* cur_plate = background_process.get_current_plate();
|
||||||
std::vector<int> f_maps = cur_plate->get_real_filament_maps(preset_bundle->project_config);
|
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());
|
background_process.fff_print()->set_extruder_filament_info(get_extruder_filament_info());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -18326,7 +18330,11 @@ void Plater::apply_background_progress()
|
|||||||
Print::ApplyStatus invalidated;
|
Print::ApplyStatus invalidated;
|
||||||
if (preset_bundle->get_printer_extruder_count() > 1) {
|
if (preset_bundle->get_printer_extruder_count() > 1) {
|
||||||
std::vector<int> f_maps = part_plate->get_real_filament_maps(preset_bundle->project_config);
|
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
|
else
|
||||||
invalidated = p->background_process.apply(this->model(), preset_bundle->full_config(false));
|
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
|
//always apply the current plate's print
|
||||||
if (preset_bundle->get_printer_extruder_count() > 1) {
|
if (preset_bundle->get_printer_extruder_count() > 1) {
|
||||||
std::vector<int> f_maps = part_plate->get_real_filament_maps(preset_bundle->project_config);
|
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
|
else
|
||||||
invalidated = p->background_process.apply(this->model(), preset_bundle->full_config(false));
|
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
|
//always apply the current plate's print
|
||||||
if (preset_bundle->get_printer_extruder_count() > 1) {
|
if (preset_bundle->get_printer_extruder_count() > 1) {
|
||||||
std::vector<int> f_maps = part_plate->get_real_filament_maps(preset_bundle->project_config);
|
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
|
else
|
||||||
invalidated = p->background_process.apply(this->model(), preset_bundle->full_config(false));
|
invalidated = p->background_process.apply(this->model(), preset_bundle->full_config(false));
|
||||||
|
|||||||
@@ -288,14 +288,15 @@ TEST_CASE("update_values_to_printer_extruders_for_multiple_filaments resolves pe
|
|||||||
REQUIRE(config.option<ConfigOptionInts>("filament_self_index")->values == std::vector<int>({1, 2}));
|
REQUIRE(config.option<ConfigOptionInts>("filament_self_index")->values == std::vector<int>({1, 2}));
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("a single-filament map matches the registered default's shape and is ignored") {
|
SECTION("a single-filament explicit assignment on a Hybrid extruder is honored") {
|
||||||
DynamicPrintConfig config = make_hybrid_printer_config();
|
DynamicPrintConfig config = make_hybrid_printer_config();
|
||||||
config.option<ConfigOptionInts>("filament_self_index", true)->values = {1, 1};
|
config.option<ConfigOptionInts>("filament_self_index", true)->values = {1, 1};
|
||||||
config.option<ConfigOptionStrings>("filament_extruder_variant", true)->values = {"Direct Drive Standard", "Direct Drive High Flow"};
|
config.option<ConfigOptionStrings>("filament_extruder_variant", true)->values = {"Direct Drive Standard", "Direct Drive High Flow"};
|
||||||
config.option<ConfigOptionFloats>("filament_max_volumetric_speed", true)->values = {12., 20.};
|
config.option<ConfigOptionFloats>("filament_max_volumetric_speed", true)->values = {12., 20.};
|
||||||
config.option<ConfigOptionInts>("filament_map", true)->values = {2};
|
config.option<ConfigOptionInts>("filament_map", true)->values = {2};
|
||||||
// sized to the (single) filament count, but indistinguishable from the registered
|
// sized to the (single) filament count: the producers guarantee sizing, so a
|
||||||
// 1-element default, so it must not override slot resolution
|
// single-filament map is as trustworthy as any other and the explicit High Flow
|
||||||
|
// request must win over the Hybrid->Standard fallback
|
||||||
config.option<ConfigOptionInts>("filament_volume_map", true)->values = {nvtHighFlow};
|
config.option<ConfigOptionInts>("filament_volume_map", true)->values = {nvtHighFlow};
|
||||||
|
|
||||||
std::vector<std::vector<NozzleVolumeType>> nozzle_volume_types;
|
std::vector<std::vector<NozzleVolumeType>> nozzle_volume_types;
|
||||||
@@ -305,8 +306,7 @@ TEST_CASE("update_values_to_printer_extruders_for_multiple_filaments resolves pe
|
|||||||
config.update_values_to_printer_extruders_for_multiple_filaments(config, extruder_count, count, filament_keys,
|
config.update_values_to_printer_extruders_for_multiple_filaments(config, extruder_count, count, filament_keys,
|
||||||
"filament_self_index", "filament_extruder_variant");
|
"filament_self_index", "filament_extruder_variant");
|
||||||
|
|
||||||
// Hybrid resolves as Standard, exactly as if no map were present
|
REQUIRE(config.option<ConfigOptionFloats>("filament_max_volumetric_speed")->values == std::vector<double>({20.}));
|
||||||
REQUIRE(config.option<ConfigOptionFloats>("filament_max_volumetric_speed")->values == std::vector<double>({12.}));
|
|
||||||
REQUIRE(config.option<ConfigOptionInts>("filament_self_index")->values == std::vector<int>({1}));
|
REQUIRE(config.option<ConfigOptionInts>("filament_self_index")->values == std::vector<int>({1}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include <catch2/catch_all.hpp>
|
#include <catch2/catch_all.hpp>
|
||||||
|
|
||||||
|
#include "libslic3r/FilamentGroupUtils.hpp"
|
||||||
#include "libslic3r/MultiNozzleUtils.hpp"
|
#include "libslic3r/MultiNozzleUtils.hpp"
|
||||||
#include "libslic3r/PrintConfig.hpp"
|
#include "libslic3r/PrintConfig.hpp"
|
||||||
#include "libslic3r/GCode/ToolOrdering.hpp"
|
#include "libslic3r/GCode/ToolOrdering.hpp"
|
||||||
@@ -348,3 +349,45 @@ TEST_CASE("NozzleStatusRecorder tracks nozzle/extruder occupancy", "[MultiNozzle
|
|||||||
// Clearing a nozzle leaves the extruder->nozzle association intact.
|
// Clearing a nozzle leaves the extruder->nozzle association intact.
|
||||||
REQUIRE(rec.get_nozzle_in_extruder(1) == 2);
|
REQUIRE(rec.get_nozzle_in_extruder(1) == 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Hybrid nozzle stats resolve to concrete volume types", "[ToolOrdering][H2C]")
|
||||||
|
{
|
||||||
|
// Extruder 0 is Standard-only; extruder 1 carries a mixed Standard + High Flow inventory
|
||||||
|
// (the "Hybrid" flow selection). The write-back pipeline persists get_volume_map(), so the
|
||||||
|
// result must always carry concrete per-filament volume types, never the Hybrid seed.
|
||||||
|
auto stats = get_extruder_nozzle_stats({"Standard#1", "Standard#1|High Flow#1"});
|
||||||
|
REQUIRE(stats.size() == 2);
|
||||||
|
REQUIRE(stats[1].size() == 2);
|
||||||
|
|
||||||
|
std::vector<unsigned int> used_filaments = {0, 1, 2};
|
||||||
|
std::vector<int> filament_map = {0, 1, 1}; // 0-based extruder ids
|
||||||
|
std::vector<int> volume_requests = {(int) nvtStandard, (int) nvtHighFlow, (int) nvtStandard};
|
||||||
|
std::vector<int> nozzle_requests = {0, 1, 2}; // distinct logical nozzles
|
||||||
|
|
||||||
|
auto group = LayeredNozzleGroupResult::create(used_filaments, filament_map, volume_requests, nozzle_requests, stats, 0.4f);
|
||||||
|
REQUIRE(group.has_value());
|
||||||
|
|
||||||
|
auto volume_map = group->get_volume_map();
|
||||||
|
REQUIRE(volume_map == volume_requests);
|
||||||
|
for (auto fid : used_filaments)
|
||||||
|
REQUIRE(volume_map[fid] != (int) nvtHybrid);
|
||||||
|
|
||||||
|
// The Hybrid seed itself matches no physical nozzle: such a request is unsatisfiable.
|
||||||
|
std::vector<int> hybrid_requests = {(int) nvtStandard, (int) nvtHybrid, (int) nvtStandard};
|
||||||
|
REQUIRE_FALSE(LayeredNozzleGroupResult::create(used_filaments, filament_map, hybrid_requests, nozzle_requests, stats, 0.4f).has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("update_used_filament_values merges only used filaments", "[ToolOrdering][H2C]")
|
||||||
|
{
|
||||||
|
// The config write-back merges the engine's per-filament values over the config baseline:
|
||||||
|
// used filaments adopt the engine value, unused filaments keep their config assignment.
|
||||||
|
std::vector<int> old_values = {1, 1, 2, 1};
|
||||||
|
std::vector<int> new_values = {2, 2, 1, 2};
|
||||||
|
std::vector<unsigned int> used = {0, 2};
|
||||||
|
|
||||||
|
auto merged = FilamentGroupUtils::update_used_filament_values(old_values, new_values, used);
|
||||||
|
REQUIRE(merged == std::vector<int>{2, 1, 1, 1});
|
||||||
|
|
||||||
|
// No used filaments => the config baseline is returned untouched.
|
||||||
|
REQUIRE(FilamentGroupUtils::update_used_filament_values(old_values, new_values, {}) == old_values);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user