mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-22 14:50:59 +00:00
refactor(imex): drop unused Split mode-type infrastructure
The mode-type tag (imex_mode_types config + imex_mode_type_for helper + Split sentinel) was added in0bb1cefas scaffolding for the Split rendering work that landed in4370ccaand then got reverted ind9be71b. With Phase 2-4 gone, this scaffolding is now unused dead code — and the design we settled on instead is to leave topology entirely implicit (parsed from active_tools_str) rather than carrying a per-mode type tag the user would otherwise have to manage explicitly. The multi-color slicing block + bare T<n> suppression that were the actual substance of the safeguards work stay in place: - imex_multicolor_block_reason still allows multi-color exactly when 2+ tools are active on the primary's gantry — Felix's hypothetical IQEX paired-gantry case works through this path, no new mode type required. - Slicer-side: bare T<n> stays suppressed at print-start in IMEX parallel modes; mid-print T<n> emits naturally for the legitimate IQEX 4-tool-active scenario. Removed: - ConfigOptionStrings imex_mode_types (PrintConfig.hpp/cpp + Preset.cpp key list) - imex_mode_type_for helper + kImexModeType{Primary,Copy,Mirror,Split} sentinels - mode_type parameter on imex_multicolor_block_reason and the Split short-circuit - mode_type plumbing in Print::validate and PartPlate::has_imex_multimaterial_conflict - Three unit tests for imex_mode_type_for + two Split-specific multicolor block tests Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
1 parent
d9be71b1ca
commit
66891899e9
8 files changed
+14
-134
No files matched your search
@@ -48,30 +48,7 @@ bool imex_suppresses_bare_toolchange(const std::string& parallel_mode, unsigned
|
||||
&& parallel_mode != kImexPrimaryMode;
|
||||
}
|
||||
|
||||
std::string imex_mode_type_for(const std::string& mode_name,
|
||||
const std::vector<std::string>& mode_names,
|
||||
const std::vector<std::string>& mode_types)
|
||||
{
|
||||
if (mode_name.empty() || mode_name == kImexPrimaryMode)
|
||||
return kImexModeTypePrimary;
|
||||
// Look up the parallel-vector entry by index match.
|
||||
for (size_t i = 0; i < mode_names.size(); ++i) {
|
||||
if (mode_names[i] != mode_name) continue;
|
||||
if (i < mode_types.size() && !mode_types[i].empty())
|
||||
return mode_types[i];
|
||||
break; // entry found but no type set → fall through to inference
|
||||
}
|
||||
// Legacy fallback: a mode literally named "copy" / "mirror" / "split" was authored
|
||||
// before imex_mode_types existed. Take the name as the type.
|
||||
if (mode_name == kImexModeTypeCopy ||
|
||||
mode_name == kImexModeTypeMirror ||
|
||||
mode_name == kImexModeTypeSplit)
|
||||
return mode_name;
|
||||
return kImexModeTypePrimary;
|
||||
}
|
||||
|
||||
std::string imex_multicolor_block_reason(const std::string& parallel_mode,
|
||||
const std::string& mode_type,
|
||||
const std::string& active_tools_str,
|
||||
int tools_per_gantry,
|
||||
const std::vector<int>& used_filaments_0b,
|
||||
@@ -84,10 +61,7 @@ std::string imex_multicolor_block_reason(const std::string& parallel_mode,
|
||||
|
||||
// MMU lane sharing detection: two or more used filaments routed to the same
|
||||
// physical head means a mid-print MMU swap on that head, which IMEX parallel
|
||||
// modes can't slave to the secondary gantry. Applies to all parallel mode
|
||||
// types including Split — even Split can't replicate MMU lane swaps across
|
||||
// gantries because the slaved gantry's physical heads can't independently
|
||||
// toolchange.
|
||||
// modes can't slave to the secondary gantry.
|
||||
if (!pem.values.empty()) {
|
||||
std::unordered_set<int> seen_physicals;
|
||||
for (int filament : used_filaments_0b) {
|
||||
@@ -103,13 +77,6 @@ std::string imex_multicolor_block_reason(const std::string& parallel_mode,
|
||||
}
|
||||
}
|
||||
|
||||
// Split modes are explicitly designed for per-gantry multi-color: each gantry
|
||||
// gets half the bed and runs its own multi-tool sequence (the slaved gantry
|
||||
// mirrors/copies the primary's sequence). The within-gantry-toolchange check
|
||||
// below doesn't apply because Split's whole purpose is to enable that.
|
||||
if (mode_type == kImexModeTypeSplit)
|
||||
return {};
|
||||
|
||||
// Determine which physical head is the primary in this mode, then count how many
|
||||
// tool roles are assigned to tools on the same gantry. Multi-color requires at
|
||||
// least 2 (so there's a within-gantry toolchange topology).
|
||||
@@ -130,8 +97,8 @@ std::string imex_multicolor_block_reason(const std::string& parallel_mode,
|
||||
return "Multi-color prints in IDEX/IQEX parallel modes require at least two tools "
|
||||
"assigned to the primary tool's gantry — there is no within-gantry "
|
||||
"toolchange path otherwise. Either reduce the print to a single filament, "
|
||||
"switch to Primary mode, or use a Split-type mode designed for per-gantry "
|
||||
"multi-color printing.";
|
||||
"switch to Primary mode, or define a parallel mode that pairs two tools on "
|
||||
"the primary gantry.";
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -105,25 +105,6 @@ int imex_pem_tool_for(int filament_id, const std::string& parallel_mode, const C
|
||||
// contains its own T<n> is handled separately by GCode.cpp's custom_gcode_changes_tool().
|
||||
bool imex_suppresses_bare_toolchange(const std::string& parallel_mode, unsigned int toolchange_count);
|
||||
|
||||
// Mode-type sentinels used by imex_mode_types entries and returned by
|
||||
// imex_mode_type_for(). Compared against to drive zone/ghost/validation behavior.
|
||||
inline constexpr const char* kImexModeTypePrimary = "primary";
|
||||
inline constexpr const char* kImexModeTypeCopy = "copy";
|
||||
inline constexpr const char* kImexModeTypeMirror = "mirror";
|
||||
inline constexpr const char* kImexModeTypeSplit = "split";
|
||||
|
||||
// Looks up the topology type ("primary" / "copy" / "mirror" / "split") for the named
|
||||
// mode. Reads from the parallel imex_mode_types vector when present; falls back to
|
||||
// inferring from the mode_name itself when the entry is missing or empty (legacy
|
||||
// presets pre-dating imex_mode_types — a mode literally named "copy" is treated as
|
||||
// a copy-type mode, etc.). Anything unknown defaults to "primary".
|
||||
//
|
||||
// `mode_name` should be the active mode being looked up. `mode_names` and `mode_types`
|
||||
// are the parallel vectors from the printer config.
|
||||
std::string imex_mode_type_for(const std::string& mode_name,
|
||||
const std::vector<std::string>& mode_names,
|
||||
const std::vector<std::string>& mode_types);
|
||||
|
||||
// Returns a user-facing block reason when multi-color printing is incompatible with
|
||||
// the active IMEX parallel mode, or an empty string when the configuration is OK.
|
||||
//
|
||||
@@ -147,16 +128,12 @@ std::string imex_mode_type_for(const std::string& mode_name,
|
||||
//
|
||||
// Inputs:
|
||||
// parallel_mode — m_imex_parallel_mode at slice time
|
||||
// mode_type — imex_mode_type_for(parallel_mode, ...). "split" types skip the
|
||||
// gantry-pair check (Split modes are explicitly designed for
|
||||
// per-gantry multi-color); MMU sharing still blocks them.
|
||||
// active_tools_str — the imex_mode_active_tools entry for the active mode, e.g.
|
||||
// "0:P,1:C,2:M,3:M"
|
||||
// tools_per_gantry — imex_tools_per_gantry from printer config (>= 1)
|
||||
// used_filaments_0b — 0-based logical filament indices used by the print
|
||||
// pem — physical_extruder_map (logical idx → physical head)
|
||||
std::string imex_multicolor_block_reason(const std::string& parallel_mode,
|
||||
const std::string& mode_type,
|
||||
const std::string& active_tools_str,
|
||||
int tools_per_gantry,
|
||||
const std::vector<int>& used_filaments_0b,
|
||||
|
||||
@@ -1044,7 +1044,7 @@ static std::vector<std::string> s_Preset_printer_options {
|
||||
// IDEX/IQEX (independent X extruder) — printer capability and user-defined modes
|
||||
"is_imex", "imex_gantry_count", "imex_tools_per_gantry", "imex_tool_layout",
|
||||
"imex_nozzle_clearance_x", "imex_nozzle_clearance_y", "imex_carriage_margin", "imex_viz_theme",
|
||||
"imex_mode_names", "imex_mode_active_tools", "imex_mode_gcodes", "imex_mode_types"
|
||||
"imex_mode_names", "imex_mode_active_tools", "imex_mode_gcodes"
|
||||
};
|
||||
|
||||
static std::vector<std::string> s_Preset_sla_print_options {
|
||||
|
||||
@@ -1216,15 +1216,12 @@ StringObjectException Print::validate(StringObjectException *warning, Polygons*
|
||||
break;
|
||||
}
|
||||
}
|
||||
const std::string mode_type = imex_mode_type_for(
|
||||
parallel_mode, mode_names, m_config.imex_mode_types.values);
|
||||
std::vector<int> used_filaments_0b;
|
||||
used_filaments_0b.reserve(extruders.size());
|
||||
for (unsigned int e : extruders)
|
||||
used_filaments_0b.push_back((int)e);
|
||||
const std::string reason = imex_multicolor_block_reason(
|
||||
parallel_mode,
|
||||
mode_type,
|
||||
active_tools_str,
|
||||
m_config.imex_tools_per_gantry.value,
|
||||
used_filaments_0b,
|
||||
|
||||
@@ -5667,20 +5667,6 @@ void PrintConfigDef::init_fff_params()
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionStrings());
|
||||
|
||||
// Mode-type tag drives how zones, ghosts, and slice-time validation interpret a
|
||||
// given mode entry. Parallel to imex_mode_names. Values: "primary", "copy",
|
||||
// "mirror", "split". Empty / missing entries fall back to "primary" except for
|
||||
// entries named "copy" or "mirror" (legacy compat with pre-type configs).
|
||||
def = this->add("imex_mode_types", coStrings);
|
||||
def->label = L("IDEX/IQEX Mode Types");
|
||||
def->tooltip = L("Per-mode topology tag. \"copy\" / \"mirror\" produce one ghost per "
|
||||
"non-primary tool at the corresponding mirrored/copied position. "
|
||||
"\"split\" splits the bed in half along the gantry axis and aggregates "
|
||||
"each gantry's tools into a single multi-color print region — used "
|
||||
"for paired-gantry IQEX multi-color printing.");
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionStrings());
|
||||
|
||||
def = this->add("manual_filament_change", coBool);
|
||||
def->label = L("Manual Filament Change");
|
||||
def->tooltip = L("Enable this option to omit the custom Change filament G-code only at the beginning of the print. "
|
||||
|
||||
@@ -1368,7 +1368,6 @@ PRINT_CONFIG_CLASS_DEFINE(
|
||||
((ConfigOptionStrings, imex_mode_names))
|
||||
((ConfigOptionStrings, imex_mode_active_tools))
|
||||
((ConfigOptionStrings, imex_mode_gcodes))
|
||||
((ConfigOptionStrings, imex_mode_types))
|
||||
((ConfigOptionBool, single_extruder_multi_material_priming))
|
||||
((ConfigOptionBool, wipe_tower_no_sparse_layers))
|
||||
((ConfigOptionString, change_filament_gcode))
|
||||
|
||||
@@ -1236,7 +1236,6 @@ bool PartPlate::has_imex_multimaterial_conflict() const
|
||||
// Resolve the active mode's tools string from the printer config.
|
||||
auto* names_opt = printer_cfg.option<ConfigOptionStrings>("imex_mode_names");
|
||||
auto* tools_opt = printer_cfg.option<ConfigOptionStrings>("imex_mode_active_tools");
|
||||
auto* types_opt = printer_cfg.option<ConfigOptionStrings>("imex_mode_types");
|
||||
auto* tpg_opt = printer_cfg.option<ConfigOptionInt>("imex_tools_per_gantry");
|
||||
auto* pem_opt = printer_cfg.option<ConfigOptionInts>("physical_extruder_map");
|
||||
if (!names_opt || !tools_opt || !tpg_opt || !pem_opt) return false;
|
||||
@@ -1249,18 +1248,13 @@ bool PartPlate::has_imex_multimaterial_conflict() const
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<std::string> empty_types;
|
||||
const std::string mode_type = imex_mode_type_for(
|
||||
mode, names_opt->values,
|
||||
types_opt ? types_opt->values : empty_types);
|
||||
|
||||
// Convert PartPlate's 1-based extruder list to the 0-based form the helper expects.
|
||||
const std::vector<int> used_1b = get_extruders(true);
|
||||
std::vector<int> used_0b;
|
||||
used_0b.reserve(used_1b.size());
|
||||
for (int e : used_1b) if (e > 0) used_0b.push_back(e - 1);
|
||||
|
||||
return !imex_multicolor_block_reason(mode, mode_type, active_tools_str, tpg_opt->value, used_0b, *pem_opt).empty();
|
||||
return !imex_multicolor_block_reason(mode, active_tools_str, tpg_opt->value, used_0b, *pem_opt).empty();
|
||||
}
|
||||
|
||||
void PartPlate::render_imex_zones(bool force_default_color)
|
||||
|
||||
@@ -116,39 +116,16 @@ TEST_CASE("imex_suppresses_bare_toolchange — parallel mode allows mid-print to
|
||||
REQUIRE_FALSE(imex_suppresses_bare_toolchange("backup_mode", 100));
|
||||
}
|
||||
|
||||
TEST_CASE("imex_mode_type_for — primary sentinel always returns primary", "[IMEX]") {
|
||||
REQUIRE(imex_mode_type_for("", {}, {}) == "primary");
|
||||
REQUIRE(imex_mode_type_for("primary", {}, {}) == "primary");
|
||||
}
|
||||
|
||||
TEST_CASE("imex_mode_type_for — explicit type from parallel array", "[IMEX]") {
|
||||
std::vector<std::string> names = {"primary", "my-copy", "my-split"};
|
||||
std::vector<std::string> types = {"primary", "copy", "split" };
|
||||
REQUIRE(imex_mode_type_for("my-copy", names, types) == "copy");
|
||||
REQUIRE(imex_mode_type_for("my-split", names, types) == "split");
|
||||
}
|
||||
|
||||
TEST_CASE("imex_mode_type_for — legacy fallback when types vector missing", "[IMEX]") {
|
||||
// Pre-imex_mode_types presets just had names. A mode literally named "copy" /
|
||||
// "mirror" / "split" maps to itself; anything else defaults to primary.
|
||||
std::vector<std::string> names = {"primary", "copy", "mirror", "split", "weird-name"};
|
||||
std::vector<std::string> types; // empty → fallback to name-based inference
|
||||
REQUIRE(imex_mode_type_for("copy", names, types) == "copy");
|
||||
REQUIRE(imex_mode_type_for("mirror", names, types) == "mirror");
|
||||
REQUIRE(imex_mode_type_for("split", names, types) == "split");
|
||||
REQUIRE(imex_mode_type_for("weird-name", names, types) == "primary");
|
||||
}
|
||||
|
||||
TEST_CASE("imex_multicolor_block_reason — non-IMEX prints never block", "[IMEX]") {
|
||||
auto pem = make_pem({0, 1, 2, 3});
|
||||
REQUIRE(imex_multicolor_block_reason("", "primary", "0:P,1:C", 2, {0, 1}, pem).empty());
|
||||
REQUIRE(imex_multicolor_block_reason("primary", "primary", "0:P,1:C", 2, {0, 1}, pem).empty());
|
||||
REQUIRE(imex_multicolor_block_reason("", "0:P,1:C", 2, {0, 1}, pem).empty());
|
||||
REQUIRE(imex_multicolor_block_reason("primary", "0:P,1:C", 2, {0, 1}, pem).empty());
|
||||
}
|
||||
|
||||
TEST_CASE("imex_multicolor_block_reason — single-color prints never block", "[IMEX]") {
|
||||
auto pem = make_pem({0, 1, 2, 3});
|
||||
REQUIRE(imex_multicolor_block_reason("copy", "copy", "0:P,1:C,2:M,3:M", 2, {0}, pem).empty());
|
||||
REQUIRE(imex_multicolor_block_reason("mirror", "mirror", "0:P,1:C,2:M,3:M", 2, {}, pem).empty());
|
||||
REQUIRE(imex_multicolor_block_reason("copy", "0:P,1:C,2:M,3:M", 2, {0}, pem).empty());
|
||||
REQUIRE(imex_multicolor_block_reason("mirror", "0:P,1:C,2:M,3:M", 2, {}, pem).empty());
|
||||
}
|
||||
|
||||
TEST_CASE("imex_multicolor_block_reason — IDEX (1 tool per gantry) blocks multi-color", "[IMEX]") {
|
||||
@@ -156,7 +133,7 @@ TEST_CASE("imex_multicolor_block_reason — IDEX (1 tool per gantry) blocks mult
|
||||
// on gantry 0, copy=T1 on gantry 1. Primary's gantry has only 1 active tool,
|
||||
// so there's no within-gantry toolchange path. Block.
|
||||
auto pem = make_pem({0, 1});
|
||||
const std::string reason = imex_multicolor_block_reason("copy", "copy", "0:P,1:C", 1, {0, 1}, pem);
|
||||
const std::string reason = imex_multicolor_block_reason("copy", "0:P,1:C", 1, {0, 1}, pem);
|
||||
REQUIRE_FALSE(reason.empty());
|
||||
REQUIRE_THAT(reason, Catch::Matchers::ContainsSubstring("primary tool's gantry"));
|
||||
}
|
||||
@@ -166,7 +143,7 @@ TEST_CASE("imex_multicolor_block_reason — IQEX 2-tool-active mode blocks multi
|
||||
// gantries). Primary's gantry (gantry 0) has only T0 active → no within-gantry
|
||||
// swap target. Block.
|
||||
auto pem = make_pem({0, 1, 2, 3});
|
||||
const std::string reason = imex_multicolor_block_reason("copy", "copy", "0:P,2:C", 2, {0, 2}, pem);
|
||||
const std::string reason = imex_multicolor_block_reason("copy", "0:P,2:C", 2, {0, 2}, pem);
|
||||
REQUIRE_FALSE(reason.empty());
|
||||
REQUIRE_THAT(reason, Catch::Matchers::ContainsSubstring("primary tool's gantry"));
|
||||
}
|
||||
@@ -176,24 +153,7 @@ TEST_CASE("imex_multicolor_block_reason — IQEX 4-tool-active multi-color allow
|
||||
// T2/T3 on gantry 1 mirroring. Primary's gantry has 2 tools active → within-
|
||||
// gantry toolchange topology is present. Used filaments {0, 1} both on gantry 0.
|
||||
auto pem = make_pem({0, 1, 2, 3});
|
||||
REQUIRE(imex_multicolor_block_reason("copy", "copy", "0:P,1:C,2:M,3:M", 2, {0, 1}, pem).empty());
|
||||
}
|
||||
|
||||
TEST_CASE("imex_multicolor_block_reason — Split mode allows multi-color regardless of gantry pair", "[IMEX]") {
|
||||
// Split modes are explicitly designed for per-gantry multi-color, so the
|
||||
// gantry-pair check is bypassed. T0+T2 with one tool per gantry would normally
|
||||
// be blocked under copy/mirror semantics, but Split allows it.
|
||||
auto pem = make_pem({0, 1, 2, 3});
|
||||
REQUIRE(imex_multicolor_block_reason("split-copy", "split", "0:P,2:C", 2, {0, 2}, pem).empty());
|
||||
}
|
||||
|
||||
TEST_CASE("imex_multicolor_block_reason — Split mode still blocks MMU sharing", "[IMEX]") {
|
||||
// Even Split can't replicate an MMU lane swap on the slaved gantry — those
|
||||
// physical heads aren't independently swappable.
|
||||
auto pem = make_pem({0, 0, 0, 0, 1, 2, 3});
|
||||
const std::string reason = imex_multicolor_block_reason("split-copy", "split", "0:P,2:C", 2, {0, 1}, pem);
|
||||
REQUIRE_FALSE(reason.empty());
|
||||
REQUIRE_THAT(reason, Catch::Matchers::ContainsSubstring("physical extruder map"));
|
||||
REQUIRE(imex_multicolor_block_reason("copy", "0:P,1:C,2:M,3:M", 2, {0, 1}, pem).empty());
|
||||
}
|
||||
|
||||
TEST_CASE("imex_multicolor_block_reason — MMU lane sharing blocks multi-color", "[IMEX]") {
|
||||
@@ -201,14 +161,14 @@ TEST_CASE("imex_multicolor_block_reason — MMU lane sharing blocks multi-color"
|
||||
// an MMU/AFC manifold. IMEX parallel modes can't slave the secondary gantry
|
||||
// through an MMU lane swap, so block.
|
||||
auto pem = make_pem({0, 0, 0, 0, 1, 2, 3});
|
||||
const std::string reason = imex_multicolor_block_reason("copy", "copy", "0:P,1:C,2:M,3:M", 2, {0, 1}, pem);
|
||||
const std::string reason = imex_multicolor_block_reason("copy", "0:P,1:C,2:M,3:M", 2, {0, 1}, pem);
|
||||
REQUIRE_FALSE(reason.empty());
|
||||
REQUIRE_THAT(reason, Catch::Matchers::ContainsSubstring("physical extruder map"));
|
||||
}
|
||||
|
||||
TEST_CASE("imex_multicolor_block_reason — mode without primary blocks", "[IMEX]") {
|
||||
auto pem = make_pem({0, 1, 2, 3});
|
||||
const std::string reason = imex_multicolor_block_reason("copy", "copy", "1:C,2:M", 2, {0, 1}, pem);
|
||||
const std::string reason = imex_multicolor_block_reason("copy", "1:C,2:M", 2, {0, 1}, pem);
|
||||
REQUIRE_FALSE(reason.empty());
|
||||
REQUIRE_THAT(reason, Catch::Matchers::ContainsSubstring("primary tool"));
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user