mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-11 01:41:03 +00:00
Bound the parallel pressure-advance lookup to the filament count
Review findings on the preceding commit, plus one defect it should have caught. - The IDEX/IQEX pressure-advance loop fed resolve_filament_for_head()'s result straight into enable_pressure_advance and pressure_advance. That result is bounded by physical_extruder_map, which holds one entry per NOZZLE, while both options are indexed per filament SLOT. On a printer with more nozzles than the project has filaments the two spaces diverge and get_at() clamped the overflow onto filament 0, emitting its pressure advance on a secondary carriage. The second-layer temperature loop bounds the same lookup, but against nozzle_temperature, which is variant-expanded and so is not the slot count either -- it is not the precedent it looks like. IMEXHelpers.hpp states the rule once, and a test pins the contract that makes the bound necessary: resolve_filament_for_head() answers in nozzle space, so a non-negative result is not by itself safe to use as a filament id. - The header claimed every caller renders a -1 tool qualifier as "emit none". RepRapFirmware substitutes the historical D0 instead, deliberately and with its own comment in GCodeWriter. Say so, rather than leaving a contract a future author would code against. - A cross-reference pointed at a hard-coded line number that the preceding commit had itself shifted by nine lines. Name the function instead. - The multi-color rejection reasons reach the user through Print::validate() as raw English, while the returns on either side of them use L(). Wrap them and register IMEXHelpers.cpp for extraction. They also still said "IMEX", the internal name, so they move to IDEX/IQEX with the rest of the user-facing strings rather than shipping the internal one to translators. - Trim the preceding commit's comments. One block explained the same clamping hazard six times; the canonical explanation now lives in IMEXHelpers.hpp and the call sites point at it. The mode grid carried twelve lines of commentary and no code, most of it archaeology already in the commit message, and one claim about the modes editor that was not true. The ArrangeJob threading note stays: it documents an invariant that cannot be recovered from the code. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
e309029b28
commit
98544fd6bc
+18
-15
@@ -3408,7 +3408,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
// pollute is_extruder_used with the *first* slot routed to the primary's
|
||||
// physical extruder, which is generally not the slot the user assigned to
|
||||
// the printing object. Same skip-primary pattern as the IMEX PA emission
|
||||
// path (GCode.cpp:3917).
|
||||
// path in _do_export().
|
||||
//
|
||||
// For secondaries: translate physical -> logical via the per-plate
|
||||
// imex_head_filament_map (set by the IMEX ghost picker), with
|
||||
@@ -3418,9 +3418,8 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
const auto plate_head_map = parse_imex_head_filament_map(
|
||||
print.objects().front()->config().imex_head_filament_map.value);
|
||||
const ConfigOptionInts& pem = print.config().physical_extruder_map;
|
||||
// Bounds-check rather than get_at(), which clamps out-of-range to values.front(). The
|
||||
// clamped value is used as a skip-primary sentinel below, so a filament id past the end
|
||||
// of the map would suppress whichever head sits at pem[0]. -1 matches no head.
|
||||
// Bounds-checked, not get_at() -- see IMEXHelpers.hpp. The value is a skip-primary
|
||||
// sentinel below, so a clamp would suppress whichever head sits at pem[0].
|
||||
const int primary_physical =
|
||||
((int) initial_extruder_id >= 0 &&
|
||||
(int) initial_extruder_id < (int) pem.values.size())
|
||||
@@ -3915,22 +3914,29 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
// loop can skip the primary head (which emitted PA via the normal path).
|
||||
// Then pem-invert each active physical head back to its first routed filament
|
||||
// for the PA setting lookup. Guarded on non-empty pem above.
|
||||
// Bounds-check rather than get_at(), which clamps out-of-range to values.front():
|
||||
// a clamped initial_physical would make this loop skip whichever active head equals
|
||||
// pem[0], leaving that head with no PA at all. Same reasoning as the second-layer
|
||||
// temperature loop below. -1 matches no head, so every active head is emitted.
|
||||
// Bounds-checked, not get_at() -- see the note on imex_pem_tool_for in
|
||||
// IMEXHelpers.hpp. A clamped initial_physical would skip whichever active head
|
||||
// equals pem[0], leaving it with no PA at all.
|
||||
const int initial_physical =
|
||||
((int) initial_extruder_id >= 0 &&
|
||||
(int) initial_extruder_id < (int) m_config.physical_extruder_map.values.size())
|
||||
? m_config.physical_extruder_map.values[(int) initial_extruder_id]
|
||||
: -1;
|
||||
const int num_pa_filament_columns = std::min(
|
||||
(int) print.config().enable_pressure_advance.values.size(),
|
||||
(int) print.config().pressure_advance.values.size());
|
||||
for (int tool_idx : get_imex_active_tools(print)) {
|
||||
// Unlike the second-layer temperature loop, the primary is skipped here:
|
||||
// set_extruder() above already emitted its PA with the pem tool qualifier.
|
||||
if (tool_idx == initial_physical) continue;
|
||||
const int logical = resolve_filament_for_head(
|
||||
m_imex_head_filament_map, m_config.physical_extruder_map, tool_idx);
|
||||
if (logical < 0) continue;
|
||||
// resolve_filament_for_head() answers in pem's index space -- one entry per
|
||||
// NOZZLE -- while these two options are indexed per FILAMENT SLOT. The spaces
|
||||
// diverge when the printer has more nozzles than the project has filaments, and
|
||||
// get_at() would clamp a past-the-end index to filament 0 and pin its PA onto a
|
||||
// secondary carriage. Same guard the second-layer temperature loop uses.
|
||||
if (logical < 0 || logical >= num_pa_filament_columns) continue;
|
||||
if (!print.config().enable_pressure_advance.get_at(logical)) continue;
|
||||
file.write(m_writer.set_pressure_advance(
|
||||
print.config().pressure_advance.get_at(logical),
|
||||
@@ -5950,12 +5956,9 @@ LayerResult GCode::process_layer(
|
||||
// transition at all. `tool_idx` is physical; the printing head uses this layer's
|
||||
// own filament, the parallel carriages resolve through the head map.
|
||||
const int num_filament_columns = (int)print.config().nozzle_temperature.values.size();
|
||||
// Bounds-check rather than get_at(): get_at() clamps to values.front(), which would
|
||||
// make initial_physical the primary's head for any first_extruder_id past the end of
|
||||
// the map. A secondary that happens to sit on that head would then take the
|
||||
// "initial" branch below and be given the wrong filament's transition temperature,
|
||||
// while never receiving its own. -1 matches no tool, so every head takes the
|
||||
// resolved path instead.
|
||||
// Bounds-checked, not get_at() -- see IMEXHelpers.hpp. A clamp would hand the
|
||||
// "initial" branch below to whichever secondary sits on pem[0], giving it the wrong
|
||||
// filament's transition temperature and never its own.
|
||||
const int initial_physical =
|
||||
((int) first_extruder_id >= 0 &&
|
||||
(int) first_extruder_id < (int) m_config.physical_extruder_map.values.size())
|
||||
|
||||
Reference in New Issue
Block a user