mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-11 18:01:14 +00:00
4fd19a5531186baaaa9c30d1fe01f72ecdd9a184
10
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
48c603faa5 |
feat(imex): firmware-managed zones — center slice + ghost suppression
Adds the `imex_firmware_managed_zones` printer-config key (default off) for IDEX/IQEX printers whose firmware applies its own copy/mirror offsets in non-primary modes (e.g. RepRapFirmware IDEX duplication mode, Flashforge Creator Pro 2/3 Pro). For these printers the slicer needs to emit a single centered slice at bed origin and let the firmware fan toolheads out from there; the previous slicer-managed iMEX rendering would draw a print at the primary zone's world position (off-bed for the firmware-fan-out paradigm). When the flag is on and the active mode is non-primary, the slicer subtracts the primary zone's plate-local center from the gcode emission frame. The writer offset is augmented but the gcode-processor offset stays at plate_origin so the gcode-preview visualizer renders the centered slice at the bed center rather than at the prepare-view zone placement. translate_to_print_space is augmented too so first_layer_print_min/max placeholders (consumed by user start_gcode like Felix's M118 header) reflect the centered frame. Slice handoff lives in PartPlate::refresh_imex_slice_offset, called from both update_slice_context (plate switch) and Plater::priv::update_background_process (every-slice path — reslice() goes through here with switch_print=false so the plate-switch hook alone wouldn't fire on mode toggle). calc_imex_ghosts early-returns in firmware-managed mode: the existing imex_head_transform math places ghosts at primary_zone_center + gantry_offset (slicer-managed semantics), which renders off-bed when the toolpath is being emitted in a centered frame. Proper firmware-managed ghost rendering (showing where copies/mirrors will actually print after firmware fan-out) is deferred. When the flag is off, all the new code paths reduce to no-ops byte-identical to prior behavior. Layer 1 unit tests in test_imex_helpers cover every gating path of compute_imex_slice_offset; full ctest suite passes (247/247). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
4966d0fae8 |
feat(imex): Span tile state for paired-gantry multicolor
Introduce ImexRole::Span as a 5th tile cycle state that declares "this tool is the multicolor partner of Primary on the same gantry." Encoded as the `S` role suffix in `imex_mode_active_tools` (e.g. `0:P,1:S,2:M,3:M`). Disambiguates paired-gantry mc-mirror from 4-independent-copies — both share the same active_tools shape sans the marker. Span drives: - Multicolor block rule: now requires Span on primary's gantry to allow multi-color slicing in a parallel mode. Replaces the prior "≥2 tools on primary's gantry" check; pre-existing 4-tool multicolor configs need T1 flipped to Span. - Ghost aggregation: one ghost per non-primary gantry when Span is present, using the column-paired representative. Aggregated-mirror drag tracks primary 1:1 in X (gantries don't share an X rail) with X-flip baked into mesh-local frame so geometry still reads as mirrored. - Zone aggregation: one full-X row strip per non-primary gantry instead of per-tool quadrants. - UI: 5th button in IMEXModesCtrl. Cycle Off→P→C→M→S→Off, only offered on multi-gantry printers and only on tiles sharing primary's gantry row. Single source of pairing truth: group_imex_active_tools_by_gantry in IMEXHelpers, consumed by ghost factory and zone calculator. Also fixes the carriage collision strip's X-boundary check, which lacked the row constraint its Y-boundary counterpart already had — paired-gantry mc-mirror was drawing a spurious right-edge strip from T3 sitting diagonally from primary. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
2c604173d3 |
fix(imex): block multi-color slicing for single-gantry "fake IMEX" modes
Catches the case where a non-primary IMEX mode's active tools all sit on one gantry — e.g. mode "0:P,1:C" on a 2x2 IQEX where T0 and T1 share gantry 0. The "Copy"/"Mirror" label is decorative there: nothing actually parallel-prints, but the user's mode_gcode still fires and emits firmware setup that doesn't apply, while the slicer treats it as a multi-color parallel print. Conceptually it's just a regular multi-tool single-gantry print and belongs in Primary mode. Changes: - imex_multicolor_block_reason now collects the set of distinct gantries spanned by the active tools and short-circuits with a clear "single gantry — not a parallel-print scenario" message before falling through to the existing within-gantry-swap check. - Drops the redundant pre-slice "Multi-material objects detected" soft warning from collect_imex_warnings — the slice-time block surfaces a more specific message at the right moment, and the soft warning was vague handwaving in front of it. Bed-temp + filament-type checks stay. - New unit test covering the single-gantry block. Behavior matrix on a 2x2 IQEX with multi-color: "0:P,1:C" single gantry -> BLOCK (new) "0:P,2:C" dual gantry, 1 each -> BLOCK (existing within-gantry-swap) "0:P,1:C,2:M,3:M" dual gantry, 2 each -> ALLOW multiple filaments to same physical via pem -> BLOCK (existing MMU sharing) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
66891899e9 |
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 in |
||
|
|
0bb1cef78e |
feat(imex): polish UI per PR feedback + add parallel-mode safeguards
Felix14-v2 PR review feedback (https://github.com/OrcaSlicer/OrcaSlicer/pull/13086#issuecomment-4323696312) plus the slice-time validation work that follows from his bug list. UI polish: - Capitalize "Primary" in display (right-click mode menu, plate tooltip). Sentinel stays lowercase for wire compatibility. - Pre-slice-warnings checkbox now uses Orca's ::CheckBox so it matches the green toggle style of the rest of the IDEX/IQEX configuration page. - DPI-scaled the IMEXModesCtrl (modes editor) sub-panels, button grid, text wraps, gcode textarea, and the ghost-tooltip swatch (imgui.scaled). Legend swatches sized to body-text height for visual balance. - Primary mode tool buttons in the modes editor are now disabled (read- only): cycling roles on the IMEX-off mode is a no-op and confusing. - Modes editor sub-panels now explicitly inherit the app's window-default dark colour so chromeless ScalableButtons don't render with a visible light box around their icons on GTK dark themes. - Per-mode-line reset arrows in the modes editor: each row gets a small reset bitmap that snaps that row's name+tools+gcode triplet back to the saved preset's value. matches_config() guard on the page-level reload prevents the textbox-being-typed-into from being destroyed mid-keystroke. - New View menu item "Show IDEX/IQEX Toolhead" — toggles the per-carriage footprint boxes during G-code preview playback. Gated to Preview tab + IMEX printer; backed by app_config so it persists. Coordinated config migrations: - imex_tool_layout and imex_viz_theme migrate from coString to coEnum (ImexToolLayout / ImexVizTheme). Existing wire format preserved so saved presets and 3MFs deserialize unchanged. Side-benefit: both now pick up standard Field rendering and so finally show reset arrows. Slice-time safeguards (the validation half): - imex_suppresses_bare_toolchange(parallel_mode, count): suppresses the slicer's bare T<n> at print-start in any IMEX parallel mode (the user's imex_mode_gcode + machine_start_gcode owns tool activation there). Mid- print T<n> emits normally — Print::validate blocks the configurations where mid-print T<n> wouldn't make sense. Applied to both code paths inside GCode::set_extruder (the long multi-extruder path AND the single-extruder path that fires when multiple_extruders=false). - imex_multicolor_block_reason(): hard-stop validator returning a user- facing reason string when the active IMEX configuration can't physically support multi-color. Catches IDEX (1 tool/gantry), 2-tool-active IQEX (no within-gantry swap topology), and any MMU/AFC lane sharing among used filaments. Wired into Print::validate as a slice blocker, and into PartPlate::has_imex_multimaterial_conflict so the plater badge agrees with the slice block (no more false positives where the badge warns but the slice goes through). - New imex_mode_types config option (parallel array to imex_mode_names) and imex_mode_type_for() helper. Mode-type tag drives behaviour: zones, ghosts, and validation interpret modes differently per type. Initial types: "primary", "copy", "mirror", "split". Split modes are explicitly designed for paired-gantry IQEX multi-color and bypass the gantry-pair check in imex_multicolor_block_reason (MMU sharing still blocks them). Test coverage: - New unit tests cover imex_suppresses_bare_toolchange (4 cases), imex_multicolor_block_reason (8 cases including IDEX, IQEX 2-/4-tool- active, MMU sharing, missing primary, Split type), and imex_mode_type_for (3 cases including legacy fallback). Total: 186 IMEX assertions across 71 test cases, all passing. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
41457635e9 |
test(imex): extract physical→logical helpers + cover them with unit tests
Three of the four IMEX physical-vs-logical fixes landed earlier on this
branch (fbc58d2a1d, fa048babeb, a38b95bf45, e11e7d46df) used inline
lambdas / direct loops to translate physical extruder indices to logical
filament slots. No test coverage existed for the specific composition,
even though the underlying primitives (resolve_filament_for_head,
first_filament_for_physical_head) were tested.
Pull two patterns out of Plater.cpp and GCode.cpp into IMEXHelpers as
named helpers, then unit-test them:
imex_primary_logical_from_objects(used_slots_1b, pem, primary_physical)
Walks the plate's used filament slots (1-based) and returns the
first one whose pem entry maps to the primary's physical extruder.
This is what the warning's `logical_for_primary` now delegates to —
moves the "look at object assignments, not pem first-routed default"
behavior introduced in fa048babeb out of the lambda and into a
separately-testable function.
imex_secondary_logical_slots(active_physicals, primary_physical,
plate_head_filament_map, pem)
Iterates IMEX active physicals, skips the one matching primary,
resolves each remainder via resolve_filament_for_head (per-plate
override + first-routed fallback), deduplicates, drops -1 entries.
Replaces the inline loop in GCode::_do_export's is_extruder_used
marking (a38b95bf45 + e11e7d46df).
10 new test cases in test_imex_helpers.cpp cover the cases that
correspond directly to bugs hit:
imex_primary_logical_from_objects:
- AFC primary picks the object's slot (the user's specific bug)
- Multi-color AFC primary returns first input-order match
- Direct extruder primary unambiguous (no MMU)
- No object routed to primary returns -1
- Empty inputs (no objects, empty pem)
imex_secondary_logical_slots:
- Copy mode skips primary, falls back to first-routed
- IQEX 4-mode enumerates all three secondaries
- Per-plate override wins over first-routed
- Drops unrouted physicals + deduplicates
- Only-primary-active returns empty
All [IMEX] + [Variant] + [3mf] regression: 166 assertions / 61 cases.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
||
|
|
c2492ccc47 |
refactor(imex): extract imex_pem_tool_for helper + unit tests
The physical_extruder_map translation used by IMEX per-tool PA emission was
inlined identically at two sites in GCode.cpp (tool-change and second-layer
transition). Extract to IMEXHelpers so the routing rule ("parallel mode AND
populated pem → physical index, else -1") is testable in isolation and the
call sites read as intent rather than re-deriving the conditional.
Production change is behavior-preserving:
- Same predicate (`!mode.empty() && mode != "primary"`)
- Same empty-pem short-circuit returning -1
- Same get_at() dispatch on hit
- Both call sites replaced with a single call
Four unit tests in [IMEX] cover the routing matrix:
- non-IMEX ("") and primary mode short-circuit
- parallel mode + empty pem short-circuits (defense-in-depth; get_at would
throw on empty values otherwise)
- identity pem (non-MMU IDEX) routes filament to itself
- MMU collapse routes multiple logical slots to one physical (7-slot profile
with 4-lane MMU on physical 0 and direct drives on 1/2/3)
All IMEX + Variant regression suites pass post-refactor (133 assertions / 48
cases under libslic3r, 25 assertions / 6 cases under fff_print [PressureAdvance]).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
||
|
|
9a87b96ded |
refactor(imex): Mirror reflects about zone-boundary plane, not primary origin
Replace imex_head_transform's fifth argument (Vec3d primary_origin) with a Vec2d primary_zone_center and rewrite the Mirror branch as a true reflection about the plane x = primary_zone_center.x + gantry_offset.x/2. Previous math flipped about the primary's current origin, which: * let the ghost drift out of the target zone as the primary moved, and * made mirrored drag motion track 1:1 with the primary instead of reflecting. The new transform places the ghost at the mirrored position within the target zone (matching where the mirror tool actually prints) and reflects drag so primary +X → ghost -X while Y tracks 1:1 — i.e. the ghost stays a true mirror while the user drags. Off-row Mirror targets (e.g. T3 on a 2x2) still reflect across the same X-plane as on-row peers. PartPlate::calc_imex_ghosts and update_imex_ghost_transforms now feed primary_off (the primary head's zone center) instead of an instance-space Vec3d. Mirror tests rewritten against the new geometric contract: ghost origin at the reflected position, primary drag deltas reflected across the zone-boundary plane. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
6a3de6a28f |
feat(imex): effective_physical_extruder_map helper + diagnostic no-filament tooltip
Centralize the project→printer→printer_extruder_id fallback for the physical extruder map. PrintApply, PartPlate (ghost color + cache key), Plater (tooltip + click gate) all previously open-coded the three-step lookup, and each handled the "pem unset, derive from pei" case slightly differently — an IDEX printer without an explicit pem could paint an UNPRINTABLE_COLOR ghost even though the slicer would have derived a valid mapping. - IMEXHelpers: add effective_physical_extruder_map(explicit_pem, pei) and a PresetBundle overload that wraps the project→printer precedence. - PrintApply: use the helper in place of the inline pei→pem normalization. - PartPlate / Plater: call the PresetBundle overload at every ghost-color, ghost-cache-key, tooltip, and click-gate site. - Plater::format_imex_ghost_tooltip: when no filament resolves to a head, surface an actionable message directing the user to extend the extruder count in the Machine tab, instead of the generic "(no filament routed)". - IMEXFilamentPickerPopover: hold m_pem by value so callers can pass a stack-local derived pem without lifetime worries. - Tests: 5 new cases covering explicit-wins, default-pem fallback, null inputs, and the IDEX ghost-color regression that motivated this. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
77c32a2e15 |
feat(imex): plate ghost renderer + per-plate filament map
Replaces the plater-icon popover with colored transparent ghost copies
of primary-head instances on the plate, one per secondary active head
under its Copy/Mirror role transform. Left-click on a ghost opens a
compact filament picker popover for the ghost's head (MMU lane override).
Ghosts track the primary through drag/rotate/scale/mirror and invalidate
on mode or pem changes.
Key pieces:
IMEXHelpers -- imex_head_transform (Primary/Copy/Mirror), shared role
parser, per-head filament resolution with X-axis Mirror anchor.
PartPlate -- ghost state, volume rebuild on mode/map/object mutation,
primary_origin plumbed for Mirror reflection across the primary-row
gantry plane.
GLCanvas3D -- ghost rendering with per-head filament color and
translucent blending; picking routed via volume composite id.
Plater -- ghost click + tooltip; plater icon left-click always cycles.
IMEXFilamentPickerPopover -- BitmapComboBox row for one secondary head,
writes imex_head_filament_map on selection.
bbs_3mf -- round-trip the per-plate imex_head_filament_map option.
PrintConfig -- add imex_head_filament_map as a plate option.
MMU/AFC routing for parallel modes relies on the printer profile's
physical_extruder_map (see prior commit for authoring format). Primary-
row heads and their per-plate filament overrides are resolved through
that map, so PA and temperature emission address the correct physical
extruder when multiple logical slots share one carriage.
Tests: IMEXHelpers coverage for Primary/Copy/Mirror transforms
including a 2x2 off-row regression guard for the X-axis reflection fix.
|