mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-07-20 09:22:13 +00:00
feat(print): add per-filament config-index resolvers and filament_map_2
- Print::get_nozzle_config_index / get_filament_config_indx resolve a filament's variant slot per layer from the nozzle group result, with hashed index caches; when no group result is published (sequential prints), they fall back to the static filament->extruder mapping so behavior is unchanged - filament_map_2 caches each filament's resolved print-variant slot; rebuilt in Print::apply after the filament_map diff handling and in the filament-map write-back - filament retract overrides now key by slot indices: apply_override fallback indexing flips to 0-based, Print::apply passes filament_map/extruder indices, the write-back passes filament_map_2 (identical resolution while slots equal extruders) - filament_volume_map/filament_nozzle_map/filament_map_2/ filament_self_index become PrintConfig static members (required for member access); grouping input guards tightened so their registered 1-element defaults are never mistaken for real per-filament maps (single-filament manual mode keeps the mix-marker fallback) - update_filament_self_index_cache refreshed at every full-config assignment - tests: 0-based apply_override fallback, get_config_index_base hit/miss/mixed-type cases The resolvers are not consumed by the g-code writer yet. Non-Hybrid g-code is unchanged except the config header, which now serializes the three new static keys (defaults until the per-filament producer lands); verified by the 19-fixture byte gate: 3 added header lines per fixture, zero motion changes.
This commit is contained in:
@@ -716,6 +716,7 @@ public:
|
||||
return false;
|
||||
}
|
||||
// Apply an override option, possibly a nullable one.
|
||||
//default_index are 0 based
|
||||
bool apply_override(const ConfigOption *rhs, std::vector<int>& default_index) override {
|
||||
if (this->nullable())
|
||||
throw ConfigurationError("Cannot override a nullable ConfigOption.");
|
||||
@@ -751,8 +752,8 @@ public:
|
||||
this->values[i] = rhs_vec->values[i];
|
||||
modified = true;
|
||||
} else {
|
||||
if ((i < default_index.size()) && (default_index[i] - 1 < default_value.size()))
|
||||
this->values[i] = default_value[default_index[i] - 1];
|
||||
if ((i < default_index.size()) && (default_index[i] < default_value.size()))
|
||||
this->values[i] = default_value[default_index[i]];
|
||||
else
|
||||
this->values[i] = default_value[0];
|
||||
}
|
||||
|
||||
@@ -1167,8 +1167,8 @@ static std::vector<MultiNozzleUtils::NozzleInfo> build_default_nozzle_list(const
|
||||
|
||||
// Best-effort readers for the multi-nozzle dev config keys. These are registered in the ConfigDef
|
||||
// but not (yet) static PrintConfig members, so the slicing PrintConfig reads them as inert defaults,
|
||||
// which keeps the auto grouping path bit-exact (all these degrade to the flush-only, non-switcher,
|
||||
// hybrid-flow case).
|
||||
// which keeps the auto grouping path bit-exact (all these degrade to the flush-only, non-switcher
|
||||
// case).
|
||||
static bool cfg_bool(const ConfigBase& c, const char* key, bool def)
|
||||
{
|
||||
if (auto* o = c.option<ConfigOptionBool>(key)) return o->value;
|
||||
@@ -1179,11 +1179,6 @@ static double cfg_float(const ConfigBase& c, const char* key, double def)
|
||||
if (auto* o = c.option<ConfigOptionFloat>(key)) return o->value;
|
||||
return def;
|
||||
}
|
||||
static std::vector<int> cfg_ints(const ConfigBase& c, const char* key)
|
||||
{
|
||||
if (auto* o = c.option<ConfigOptionInts>(key)) return o->values;
|
||||
return {};
|
||||
}
|
||||
|
||||
// Prepare per-extruder flush matrices. The prime_volume_mode==pvmFast branch: Default reads
|
||||
// flush_multiplier, Fast reads flush_multiplier_fast.
|
||||
@@ -1336,19 +1331,17 @@ static FilamentGroupContext build_filament_group_context(
|
||||
context.group_info.ignore_ext_filament = ignore_ext_filament;
|
||||
context.group_info.has_filament_switcher = has_filament_switcher;
|
||||
|
||||
// hybrid flow means no special per-filament nozzle-volume request. In manual mode we honour the
|
||||
// config's per-filament volume map when it is present and correctly sized; otherwise (the key is
|
||||
// not a static PrintConfig member) fall back to hybrid so rebuild_nozzle_unprintables
|
||||
// never indexes out of range.
|
||||
if (mode == FilamentMapMode::fmmManual) {
|
||||
auto fvm = cfg_ints(print_config, "filament_volume_map");
|
||||
if (fvm.size() == filament_nums)
|
||||
context.group_info.filament_volume_map = std::move(fvm);
|
||||
else
|
||||
context.group_info.filament_volume_map = std::vector<int>(filament_nums, (int)(NozzleVolumeType::nvtHybrid));
|
||||
} else {
|
||||
// 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
|
||||
// sized it to a multi-filament count (the trust guard used by
|
||||
// update_values_to_printer_extruders_for_multiple_filaments): the registered default is a
|
||||
// 1-element vector ({Standard}) that a single-filament count cannot tell apart from a real
|
||||
// map, and it must not displace the hybrid fallback rebuild_nozzle_unprintables relies on.
|
||||
if (mode == FilamentMapMode::fmmManual && filament_nums > 1 &&
|
||||
print_config.filament_volume_map.values.size() == filament_nums)
|
||||
context.group_info.filament_volume_map = print_config.filament_volume_map.values;
|
||||
else
|
||||
context.group_info.filament_volume_map = std::vector<int>(filament_nums, (int)(NozzleVolumeType::nvtHybrid));
|
||||
}
|
||||
|
||||
context.nozzle_info.nozzle_list = build_nozzle_list(nozzle_groups);
|
||||
context.nozzle_info.extruder_nozzle_list = build_extruder_nozzle_list(context.nozzle_info.nozzle_list);
|
||||
@@ -1493,7 +1486,17 @@ MultiNozzleUtils::LayeredNozzleGroupResult ToolOrdering::get_recommended_filamen
|
||||
auto manual_filament_map = print_config.filament_map.values;
|
||||
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();
|
||||
auto nozzle_result = LayeredNozzleGroupResult::create(used_filaments, manual_filament_map, cfg_ints(print_config, "filament_volume_map"), cfg_ints(print_config, "filament_nozzle_map"), get_extruder_nozzle_stats(print_config.extruder_nozzle_stats.values), diameter);
|
||||
// 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
|
||||
// 1-element defaults are indistinguishable by size from a real single-filament map.
|
||||
// Without valid maps the fully-manual request cannot be honoured; return the empty result,
|
||||
// the same failure an unsatisfiable create() yields.
|
||||
std::optional<LayeredNozzleGroupResult> nozzle_result;
|
||||
if (filament_nums > 1 && print_config.filament_volume_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);
|
||||
if (!nozzle_result)
|
||||
BOOST_LOG_TRIVIAL(error) << "Failed to build nozzle group result from filament nozzle map!";
|
||||
return nozzle_result ? *nozzle_result : LayeredNozzleGroupResult();
|
||||
}
|
||||
|
||||
@@ -1611,11 +1614,18 @@ static MultiNozzleUtils::LayeredNozzleGroupResult build_group_result_from_map(
|
||||
{
|
||||
using namespace MultiNozzleUtils;
|
||||
const size_t extruder_nums = print_config.nozzle_diameter.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(),
|
||||
[](int v) { return v > 1; });
|
||||
if (has_multiple_nozzle) {
|
||||
// Orca: same trust 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
|
||||
// be mistaken for a real single-filament map. Unsized maps fall through to the extruder-level
|
||||
// wrap below.
|
||||
if (has_multiple_nozzle && filament_nums > 1 &&
|
||||
print_config.filament_volume_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());
|
||||
if (auto g = LayeredNozzleGroupResult::create(used_filaments, filament_map_0based, cfg_ints(print_config, "filament_volume_map"), cfg_ints(print_config, "filament_nozzle_map"), get_extruder_nozzle_stats(print_config.extruder_nozzle_stats.values), diameter))
|
||||
if (auto g = LayeredNozzleGroupResult::create(used_filaments, filament_map_0based, print_config.filament_volume_map.values, print_config.filament_nozzle_map.values, get_extruder_nozzle_stats(print_config.extruder_nozzle_stats.values), diameter))
|
||||
return *g;
|
||||
}
|
||||
auto nozzle_list = build_default_nozzle_list(print_config, extruder_nums);
|
||||
|
||||
@@ -3211,6 +3211,29 @@ void Print::update_filament_maps_to_config(std::vector<int> f_maps)
|
||||
std::vector<std::vector<NozzleVolumeType>> nozzle_volume_types;
|
||||
extruder_volume_type_count = m_ori_full_print_config.get_extruder_nozzle_volume_count(extruder_count, nozzle_volume_types);
|
||||
|
||||
//filament_map_2
|
||||
// Orca: seed with 0-based extruder indices so the override keying below degenerates to the
|
||||
// plain per-extruder slot when the rebuild loop is skipped; the loop overwrites every
|
||||
// entry when it runs.
|
||||
m_config.filament_map_2.values = f_maps;
|
||||
for (auto& v : m_config.filament_map_2.values)
|
||||
--v;
|
||||
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"));
|
||||
// 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
|
||||
// grouping engine does not produce per-filament volume maps yet, so m_config only carries
|
||||
// a map when the project supplied one.
|
||||
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));
|
||||
NozzleVolumeType nozzle_volume_type = (NozzleVolumeType)(opt_nozzle_volume_type->get_at(f_maps[index] - 1));
|
||||
if ((extruder_volume_type_count > extruder_count)
|
||||
&& f_maps.size() > 1 && m_config.filament_volume_map.values.size() == f_maps.size())
|
||||
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_full_print_config = m_ori_full_print_config;
|
||||
std::set<std::string> filament_keys = filament_options_with_variant;
|
||||
filament_keys.insert("filament_self_index");
|
||||
@@ -3228,7 +3251,7 @@ void Print::update_filament_maps_to_config(std::vector<int> f_maps)
|
||||
const ConfigOption *opt_old_machine = m_config.option(opt_key);
|
||||
|
||||
if (opt_new_filament)
|
||||
compute_filament_override_value(opt_key, opt_old_machine, opt_new_machine, opt_new_filament, m_full_print_config, print_diff, filament_overrides, 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);
|
||||
}
|
||||
|
||||
t_config_option_keys keys(filament_options_with_variant.begin(), filament_options_with_variant.end());
|
||||
@@ -3238,6 +3261,7 @@ void Print::update_filament_maps_to_config(std::vector<int> f_maps)
|
||||
m_config.apply(filament_overrides);
|
||||
}
|
||||
}
|
||||
update_filament_self_index_cache();
|
||||
m_has_auto_filament_map_result = true;
|
||||
}
|
||||
|
||||
@@ -3251,6 +3275,16 @@ std::vector<int> Print::get_filament_maps() const
|
||||
return m_config.filament_map.values;
|
||||
}
|
||||
|
||||
std::vector<int> Print::get_filament_nozzle_maps() const
|
||||
{
|
||||
return m_config.filament_nozzle_map.values;
|
||||
}
|
||||
|
||||
std::vector<int> Print::get_filament_volume_maps() const
|
||||
{
|
||||
return m_config.filament_volume_map.values;
|
||||
}
|
||||
|
||||
FilamentMapMode Print::get_filament_map_mode() const
|
||||
{
|
||||
return m_config.filament_map_mode;
|
||||
@@ -3405,6 +3439,108 @@ bool Print::is_dynamic_group_reorder() const
|
||||
return true;
|
||||
}
|
||||
|
||||
int Print::get_filament_config_indx(int filament_id, int layer_id)
|
||||
{
|
||||
return get_config_index(filament_id, layer_id, m_config.filament_extruder_variant.values, m_filament_self_index, m_filament_index_map);
|
||||
}
|
||||
|
||||
void Print::update_filament_self_index_cache()
|
||||
{
|
||||
std::vector<int> values;
|
||||
if (m_full_print_config.has("filament_self_index")) {
|
||||
values = m_full_print_config.option<ConfigOptionInts>("filament_self_index")->values;
|
||||
} else if (m_ori_full_print_config.has("filament_self_index")) {
|
||||
values = m_ori_full_print_config.option<ConfigOptionInts>("filament_self_index")->values;
|
||||
} else {
|
||||
values = m_config.filament_self_index.values;
|
||||
}
|
||||
|
||||
size_t expected_size = m_config.filament_extruder_variant.values.size();
|
||||
m_filament_self_index.clear();
|
||||
if (expected_size == 0) {
|
||||
m_filament_index_map.clear();
|
||||
m_nozzle_index_map.clear();
|
||||
return;
|
||||
}
|
||||
m_filament_self_index.resize(expected_size, 1);
|
||||
if (!values.empty()) {
|
||||
for (size_t i = 0; i < expected_size; ++i) {
|
||||
int v = i < values.size() ? values[i] : 1;
|
||||
if (v <= 0)
|
||||
v = 1;
|
||||
m_filament_self_index[i] = v;
|
||||
}
|
||||
}
|
||||
m_filament_index_map.clear();
|
||||
m_nozzle_index_map.clear();
|
||||
}
|
||||
|
||||
int Print::get_nozzle_config_index(int filament_id, int layer_id)
|
||||
{
|
||||
// Orca: print_extruder_id/print_extruder_variant are PrintRegionConfig members in this codebase;
|
||||
// the process-wide expanded values live in the default region config (regions never override them).
|
||||
return get_config_index(filament_id, layer_id, m_default_region_config.print_extruder_variant.values, m_default_region_config.print_extruder_id.values, m_nozzle_index_map);
|
||||
}
|
||||
|
||||
int Print::get_config_index(int filament_id, int layer_id, const std::vector<std::string> &variant_list, const std::vector<int>& self_index_list, FilamentIndexMap &index_map)
|
||||
{
|
||||
auto group_result = get_layered_nozzle_group_result();
|
||||
// Orca: sequential (by-object) prints never publish a Print-level layered group result on this
|
||||
// branch, so fall back to the static identity: one filament-variant column per filament.
|
||||
if (!group_result)
|
||||
return filament_id;
|
||||
auto nozzle_info = group_result->get_nozzle_for_filament(filament_id, layer_id);
|
||||
if (!nozzle_info.has_value()) {
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__
|
||||
<< boost::format(", Line %1%: could not found group_nozzle_info corresponding to filament_id %2%, layer_id %3%") % __LINE__ % filament_id %
|
||||
layer_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ExtruderType extruder_type = ExtruderType(m_config.extruder_type.get_at(nozzle_info->extruder_id));
|
||||
NozzleVolumeType nozzle_volume_type = nozzle_info->volume_type;
|
||||
|
||||
FilamentIndexKey key{filament_id, extruder_type, nozzle_volume_type};
|
||||
auto iter = index_map.find(key);
|
||||
if (iter == index_map.end()) {
|
||||
int index = get_config_index_base(nozzle_volume_type, extruder_type, filament_id + 1, variant_list, self_index_list);
|
||||
index_map[key] = index;
|
||||
return index;
|
||||
} else {
|
||||
return index_map[key];
|
||||
}
|
||||
}
|
||||
|
||||
int Print::get_config_index(int filament_id, int layer_id, const std::vector<std::string> &variant_list, const std::vector<int>& self_index_list, PrintIndexMap &index_map)
|
||||
{
|
||||
auto group_result = get_layered_nozzle_group_result();
|
||||
// Orca: same static fallback as the filament overload; the slot degenerates to the filament's
|
||||
// extruder column (filament_map is 1 based, get_extruder_id guards the filament id range).
|
||||
if (!group_result)
|
||||
return (int)get_extruder_id(filament_id);
|
||||
auto nozzle_info = group_result->get_nozzle_for_filament(filament_id, layer_id);
|
||||
if (!nozzle_info.has_value()) {
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__
|
||||
<< boost::format(", Line %1%: could not found group_nozzle_info corresponding to filament_id %2%, layer_id %3%") % __LINE__ % filament_id %
|
||||
layer_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int extruder_id = nozzle_info->extruder_id + 1; // to 1 based
|
||||
ExtruderType extruder_type = ExtruderType(m_config.extruder_type.get_at(nozzle_info->extruder_id));
|
||||
NozzleVolumeType nozzle_volume_type = nozzle_info->volume_type;
|
||||
|
||||
PrintIndexKey key{filament_id, extruder_id, extruder_type, nozzle_volume_type};
|
||||
auto iter = index_map.find(key);
|
||||
if (iter == index_map.end()) {
|
||||
int index = get_config_index_base(nozzle_volume_type, extruder_type, extruder_id, variant_list, self_index_list);
|
||||
index_map[key] = index;
|
||||
return index;
|
||||
} else {
|
||||
return index_map[key];
|
||||
}
|
||||
}
|
||||
|
||||
// Wipe tower support.
|
||||
bool Print::has_wipe_tower() const
|
||||
{
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
#include <functional>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "calib.hpp"
|
||||
|
||||
@@ -1010,6 +1011,8 @@ public:
|
||||
// 1 based group ids
|
||||
std::vector<int> get_filament_maps() const;
|
||||
FilamentMapMode get_filament_map_mode() const;
|
||||
std::vector<int> get_filament_volume_maps() const;
|
||||
std::vector<int> get_filament_nozzle_maps() const;
|
||||
// get the group label of filament
|
||||
size_t get_extruder_id(unsigned int filament_id) const;
|
||||
|
||||
@@ -1152,7 +1155,12 @@ public:
|
||||
bool is_all_objects_are_short() const {
|
||||
return std::all_of(this->objects().begin(), this->objects().end(), [&](PrintObject* obj) { return obj->height() < scale_(this->config().nozzle_height.value); });
|
||||
}
|
||||
|
||||
|
||||
// Post-slicing config-slot resolvers: map a (filament, layer) pair to the index of its
|
||||
// per-(extruder x volume type) column in the expanded variant arrays, cached by grouping context.
|
||||
int get_filament_config_indx(int filament_id, int layer_id);
|
||||
int get_nozzle_config_index(int filament_id, int layer_id);
|
||||
|
||||
// Orca: Implement prusa's filament shrink compensation approach
|
||||
// Returns if all used filaments have same shrinkage compensations.
|
||||
bool has_same_shrinkage_compensations() const;
|
||||
@@ -1162,6 +1170,57 @@ public:
|
||||
std::tuple<float, float> object_skirt_offset(double margin_height = 0) const;
|
||||
|
||||
protected:
|
||||
struct FilamentIndexKey
|
||||
{
|
||||
int filament_id;
|
||||
ExtruderType extruder;
|
||||
NozzleVolumeType nozzle_volume_type;
|
||||
|
||||
bool operator==(const FilamentIndexKey &other) const
|
||||
{
|
||||
return filament_id == other.filament_id && extruder == other.extruder && nozzle_volume_type == other.nozzle_volume_type;
|
||||
}
|
||||
};
|
||||
|
||||
struct PrintIndexKey
|
||||
{
|
||||
int filament_id;
|
||||
int extruder_id;
|
||||
ExtruderType extruder;
|
||||
NozzleVolumeType nozzle_volume_type;
|
||||
|
||||
bool operator==(const PrintIndexKey &other) const
|
||||
{
|
||||
return filament_id == other.filament_id && extruder_id == other.extruder_id && extruder == other.extruder && nozzle_volume_type == other.nozzle_volume_type;
|
||||
}
|
||||
};
|
||||
|
||||
struct FilamentIndexKeyHash
|
||||
{
|
||||
std::size_t operator()(const FilamentIndexKey &k) const
|
||||
{
|
||||
size_t h1 = std::hash<int>{}(k.filament_id);
|
||||
size_t h2 = std::hash<int>{}(static_cast<int>(k.extruder));
|
||||
size_t h3 = std::hash<int>{}(static_cast<int>(k.nozzle_volume_type));
|
||||
return h1 ^ (h2 << 8) ^ (h3 << 12);
|
||||
}
|
||||
};
|
||||
struct PrintIndexKeyHash
|
||||
{
|
||||
std::size_t operator()(const PrintIndexKey &k) const
|
||||
{
|
||||
size_t h1 = std::hash<int>{}(k.filament_id);
|
||||
size_t h2 = std::hash<int>{}(k.extruder_id);
|
||||
size_t h3 = std::hash<int>{}(static_cast<int>(k.extruder));
|
||||
size_t h4 = std::hash<int>{}(static_cast<int>(k.nozzle_volume_type));
|
||||
return h1 ^ (h2 << 8) ^ (h3 << 12) ^ (h4 << 16);
|
||||
}
|
||||
};
|
||||
using FilamentIndexMap = std::unordered_map<FilamentIndexKey, int, FilamentIndexKeyHash>;
|
||||
using PrintIndexMap = std::unordered_map<PrintIndexKey, int, PrintIndexKeyHash>;
|
||||
int get_config_index(int filament_id, int layer_id, const std::vector<std::string> &variant_list, const std::vector<int>& self_index_list, FilamentIndexMap &index_map);
|
||||
int get_config_index(int filament_id, int layer_id, const std::vector<std::string> &variant_list, const std::vector<int>& self_index_list, PrintIndexMap &index_map);
|
||||
|
||||
// Invalidates the step, and its depending steps in Print.
|
||||
bool invalidate_step(PrintStep step);
|
||||
|
||||
@@ -1175,6 +1234,7 @@ private:
|
||||
void _make_skirt();
|
||||
void _make_wipe_tower();
|
||||
void finalize_first_layer_convex_hull();
|
||||
void update_filament_self_index_cache();
|
||||
|
||||
// Islands of objects and their supports extruded at the 1st layer.
|
||||
Polygons first_layer_islands() const;
|
||||
@@ -1211,6 +1271,13 @@ private:
|
||||
// Logical (extruder, nozzle) grouping result, set by ToolOrdering during reorder.
|
||||
std::shared_ptr<MultiNozzleUtils::NozzleGroupResultBase> m_nozzle_group_result;
|
||||
|
||||
// Used to cache filament parameter information
|
||||
FilamentIndexMap m_filament_index_map;
|
||||
// Used to cache printer and process parameter information
|
||||
PrintIndexMap m_nozzle_index_map;
|
||||
// save the config value of "filament_self_index"
|
||||
std::vector<int> m_filament_self_index;
|
||||
|
||||
// Following section will be consumed by the GCodeGenerator.
|
||||
ToolOrdering m_tool_ordering;
|
||||
WipeTowerData m_wipe_tower_data {m_tool_ordering};
|
||||
|
||||
@@ -240,7 +240,10 @@ static t_config_option_keys print_config_diffs(
|
||||
const ConfigOption *opt_new_filament = std::binary_search(extruder_retract_keys.begin(), extruder_retract_keys.end(), opt_key) ? new_full_config.option(filament_prefix + opt_key) : nullptr;
|
||||
|
||||
if (opt_new_filament != nullptr) {
|
||||
compute_filament_override_value(opt_key, opt_old, opt_new, opt_new_filament, new_full_config, print_diff, filament_overrides, filament_maps);
|
||||
std::vector<int> filament_map_indices(filament_maps.size(), 0);
|
||||
for (int i = 0; i < filament_maps.size(); i++)
|
||||
filament_map_indices[i] = filament_maps[i] - 1;
|
||||
compute_filament_override_value(opt_key, opt_old, opt_new, opt_new_filament, new_full_config, print_diff, filament_overrides, filament_map_indices);
|
||||
} else if (*opt_new != *opt_old) {
|
||||
//BBS: add plate_index logic for wipe_tower_x/wipe_tower_y
|
||||
if (!opt_key.compare("wipe_tower_x") || !opt_key.compare("wipe_tower_y")) {
|
||||
@@ -1248,6 +1251,29 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
||||
print_diff.assign(print_diff_set.begin(), print_diff_set.end());
|
||||
}
|
||||
|
||||
//filament_map_2
|
||||
// Orca: seed with 0-based extruder indices so the copy stays a valid slot map even when the
|
||||
// variant options are absent below and the rebuild loop is skipped (unit tests, degenerate
|
||||
// presets); the loop overwrites every entry when it runs.
|
||||
m_config.filament_map_2.values = filament_maps;
|
||||
for (auto& v : m_config.filament_map_2.values)
|
||||
--v;
|
||||
auto opt_extruder_type = dynamic_cast<const ConfigOptionEnumsGeneric*>(new_full_config.option("extruder_type"));
|
||||
auto opt_filament_volume_maps = dynamic_cast<const ConfigOptionInts*>(new_full_config.option("filament_volume_map"));
|
||||
auto opt_nozzle_volume_type = dynamic_cast<const ConfigOptionEnumsGeneric*>(new_full_config.option("nozzle_volume_type"));
|
||||
for (int index = 0; opt_extruder_type && opt_nozzle_volume_type && index < filament_maps.size(); index++)
|
||||
{
|
||||
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));
|
||||
// Orca: the per-filament volume map is only trustworthy when a producer explicitly sized it
|
||||
// to the filament count; the registered default is a 1-element vector (see
|
||||
// update_values_to_printer_extruders_for_multiple_filaments for the same guard).
|
||||
if ((extruder_volume_type_count > extruder_count) && opt_filament_volume_maps
|
||||
&& filament_maps.size() > 1 && opt_filament_volume_maps->values.size() == filament_maps.size())
|
||||
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");
|
||||
}
|
||||
|
||||
// Do not use the ApplyStatus as we will use the max function when updating apply_status.
|
||||
unsigned int apply_status = APPLY_STATUS_UNCHANGED;
|
||||
auto update_apply_status = [&apply_status](bool invalidated)
|
||||
@@ -1295,6 +1321,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
||||
m_default_region_config.apply_only(new_full_config, region_diff, true);
|
||||
//m_full_print_config = std::move(new_full_config);
|
||||
m_full_print_config = new_full_config;
|
||||
update_filament_self_index_cache();
|
||||
if (num_extruders != m_config.filament_diameter.size()) {
|
||||
num_extruders = m_config.filament_diameter.size();
|
||||
num_extruders_changed = true;
|
||||
@@ -1668,6 +1695,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
||||
// Handle changes to regions config defaults
|
||||
m_default_region_config.apply_only(new_full_config, new_changed_keys, true);
|
||||
m_full_print_config = std::move(new_full_config);
|
||||
update_filament_self_index_cache();
|
||||
}
|
||||
|
||||
// All regions now have distinct settings.
|
||||
|
||||
@@ -2731,10 +2731,9 @@ void PrintConfigDef::init_fff_params()
|
||||
def->set_default_value(new ConfigOptionInts{1});
|
||||
|
||||
// Multi-nozzle: per-filament map to the config slot identified by (extruder, nozzle_volume_type).
|
||||
// Forward-compat-only registration with no consumer yet.
|
||||
// Orca: resolves per-variant slots via get_index_for_extruder at PrintApply time rather than a
|
||||
// read-time filament-config-index lookup, so nothing in src/ reads this key. Kept registered so an
|
||||
// H2C project/config that carries it loads without an unknown-option substitution warning.
|
||||
// Engine-internal per-filament slot map: recomputed at apply time from filament_map (plus the
|
||||
// per-filament volume map when an extruder exposes several volume types) and used to key the
|
||||
// retract-override fallback; never a user input and never part of the exported full config.
|
||||
// Internal use only, no translation.
|
||||
def = this->add("filament_map_2", coInts);
|
||||
def->label = "Filament map plus for multi nozzle";
|
||||
@@ -2742,9 +2741,10 @@ void PrintConfigDef::init_fff_params()
|
||||
def->mode = comDevelop;
|
||||
def->set_default_value(new ConfigOptionInts{1});
|
||||
|
||||
// Per-filament nozzle-volume-type override (multi-volume/Hybrid). Registered so the value
|
||||
// round-trips through .3mf plate metadata (filament_volume_maps); load/save-only for now and
|
||||
// inert for existing printers (unread by slicing until the multi-volume pipeline lands).
|
||||
// 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
|
||||
// extruder exposes several volume types; inert for existing printers (no producer sizes it
|
||||
// to the filament count until the write-back pipeline lands).
|
||||
def = this->add("filament_volume_map", coInts);
|
||||
def->mode = comDevelop;
|
||||
def->set_default_value(new ConfigOptionInts{(int)(NozzleVolumeType::nvtStandard)});
|
||||
@@ -11030,7 +11030,7 @@ void DynamicPrintConfig::update_diff_values_to_child_config(DynamicPrintConfig&
|
||||
}
|
||||
|
||||
void compute_filament_override_value(const std::string& opt_key, const ConfigOption *opt_old_machine, const ConfigOption *opt_new_machine, const ConfigOption *opt_new_filament, const DynamicPrintConfig& new_full_config,
|
||||
t_config_option_keys& diff_keys, DynamicPrintConfig& filament_overrides, std::vector<int>& f_maps)
|
||||
t_config_option_keys& diff_keys, DynamicPrintConfig& filament_overrides, std::vector<int>& f_map_indices)
|
||||
{
|
||||
bool is_nil = opt_new_filament->is_nil();
|
||||
|
||||
@@ -11052,7 +11052,7 @@ void compute_filament_override_value(const std::string& opt_key, const ConfigOpt
|
||||
}
|
||||
|
||||
auto opt_copy = opt_new_machine->clone();
|
||||
opt_copy->apply_override(opt_new_filament, f_maps);
|
||||
opt_copy->apply_override(opt_new_filament, f_map_indices);
|
||||
bool changed = *opt_old_machine != *opt_copy;
|
||||
|
||||
if (changed) {
|
||||
|
||||
@@ -774,7 +774,7 @@ extern std::set<std::string> printer_options_with_variant_2;
|
||||
extern std::set<std::string> empty_options;
|
||||
|
||||
extern void compute_filament_override_value(const std::string& opt_key, const ConfigOption *opt_old_machine, const ConfigOption *opt_new_machine, const ConfigOption *opt_new_filament, const DynamicPrintConfig& new_full_config,
|
||||
t_config_option_keys& diff_keys, DynamicPrintConfig& filament_overrides, std::vector<int>& f_maps);
|
||||
t_config_option_keys& diff_keys, DynamicPrintConfig& filament_overrides, std::vector<int>& f_map_indices);
|
||||
|
||||
void handle_legacy_sla(DynamicPrintConfig &config);
|
||||
|
||||
@@ -1447,8 +1447,12 @@ PRINT_CONFIG_CLASS_DEFINE(
|
||||
((ConfigOptionInts, required_nozzle_HRC))
|
||||
((ConfigOptionEnum<FilamentMapMode>, filament_map_mode))
|
||||
((ConfigOptionInts, filament_map))
|
||||
((ConfigOptionInts, filament_volume_map))
|
||||
((ConfigOptionInts, filament_nozzle_map))
|
||||
((ConfigOptionInts, filament_map_2)) //used for multi nozzle, map filament to the index identified by extruder+nozzle_volume_type
|
||||
//((ConfigOptionInts, filament_extruder_id))
|
||||
((ConfigOptionStrings, filament_extruder_variant))
|
||||
((ConfigOptionInts, filament_self_index))
|
||||
((ConfigOptionBool, support_object_skip_flush))
|
||||
((ConfigOptionEnum<BedTempFormula>, bed_temperature_formula))
|
||||
((ConfigOptionInts, physical_extruder_map))
|
||||
|
||||
@@ -30,6 +30,57 @@ void add_print_variant_columns(DynamicPrintConfig &config)
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("apply_override fills nil entries from the 0-based default index", "[Config]")
|
||||
{
|
||||
ConfigOptionFloats machine({10., 20., 30.});
|
||||
ConfigOptionFloatsNullable filament;
|
||||
filament.values = {ConfigOptionFloatsNullable::nil_value(), 42.};
|
||||
|
||||
SECTION("a nil entry picks the slot addressed by its 0-based index") {
|
||||
std::vector<int> slot_index{2, 0};
|
||||
ConfigOptionFloats resolved(machine);
|
||||
REQUIRE(resolved.apply_override(&filament, slot_index));
|
||||
REQUIRE(resolved.values == std::vector<double>({30., 42.}));
|
||||
}
|
||||
|
||||
SECTION("an index past the machine slots falls back to the first slot") {
|
||||
std::vector<int> slot_index{5, 0};
|
||||
ConfigOptionFloats resolved(machine);
|
||||
REQUIRE(resolved.apply_override(&filament, slot_index));
|
||||
REQUIRE(resolved.values == std::vector<double>({10., 42.}));
|
||||
}
|
||||
|
||||
SECTION("a negative index (unresolved slot) falls back to the first slot") {
|
||||
std::vector<int> slot_index{-1, 0};
|
||||
ConfigOptionFloats resolved(machine);
|
||||
REQUIRE(resolved.apply_override(&filament, slot_index));
|
||||
REQUIRE(resolved.values == std::vector<double>({10., 42.}));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("get_config_index_base resolves (volume type, extruder type, id) to a slot", "[Config]")
|
||||
{
|
||||
const std::vector<std::string> variant_list = {"Direct Drive Standard", "Direct Drive High Flow",
|
||||
"Direct Drive Standard", "Direct Drive High Flow"};
|
||||
const std::vector<int> variant_ids = {1, 1, 2, 2};
|
||||
|
||||
SECTION("a matching (variant, id) pair yields its slot") {
|
||||
REQUIRE(get_config_index_base(nvtStandard, etDirectDrive, 1, variant_list, variant_ids) == 0);
|
||||
REQUIRE(get_config_index_base(nvtHighFlow, etDirectDrive, 1, variant_list, variant_ids) == 1);
|
||||
REQUIRE(get_config_index_base(nvtStandard, etDirectDrive, 2, variant_list, variant_ids) == 2);
|
||||
REQUIRE(get_config_index_base(nvtHighFlow, etDirectDrive, 2, variant_list, variant_ids) == 3);
|
||||
}
|
||||
|
||||
SECTION("no matching column falls back to slot 0") {
|
||||
REQUIRE(get_config_index_base(nvtStandard, etDirectDrive, 3, variant_list, variant_ids) == 0);
|
||||
REQUIRE(get_config_index_base(nvtStandard, etBowden, 1, variant_list, variant_ids) == 0);
|
||||
}
|
||||
|
||||
SECTION("Hybrid is not a preset variant string and falls back to slot 0") {
|
||||
REQUIRE(get_config_index_base(nvtHybrid, etDirectDrive, 2, variant_list, variant_ids) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("get_extruder_nozzle_volume_count reads the per-extruder volume-type layout", "[Config]")
|
||||
{
|
||||
std::vector<std::vector<NozzleVolumeType>> nozzle_volume_types;
|
||||
|
||||
Reference in New Issue
Block a user