Skip to content

feat: block slicing when filament flow ratio is 0 (with per-filament breakdown) - #626

Open
iesteem wants to merge 8 commits into
mainfrom
fix_flow_ratio
Open

feat: block slicing when filament flow ratio is 0 (with per-filament breakdown)#626
iesteem wants to merge 8 commits into
mainfrom
fix_flow_ratio

Conversation

@iesteem

@iesteem iesteem commented Jul 27, 2026

Copy link
Copy Markdown

Summary

Block slicing when any actually-used filament on a plate has filament_flow_ratio == 0, and surface a ValidateError notification listing the offending filament slots (e.g. [3] Snapmaker PLA Basic @U1) — fully aligned with the existing filament-temperature-mixing blocker. Goal: turn the "zero extrusion → empty toolpath" silent failure into a visible pre-slice error.

The PR also bundles a few related minor fixes (see "Related fixes" below).

Core changes

Flow-ratio-zero blocking core (Plater.cpp / Plater.hpp)

  • New FlowRatioZeroDetail { offender_slots_1based }; slots are 1-based to match the UI.
  • check_flow_ratio_zero(plate_index[, detail]): boundary checks + only when the plate has objects, collect the actually-used filament slots (same collection logic as check_filament_temp_mixing); read each preset's filament_flow_ratio, treat <= 0.0 as offender.
  • is_plate_blocked_by_flow_ratio_zero(): exposed to MainFrame / GLCanvas3D for slice-button greying and plate-toolbar SLICE_FAILED state.
  • sync_flow_ratio_zero_notification(): close-then-push pattern; caches flow_ratio_zero_last_error_text to match close_validate_error_notification's exact-text matching; does not touch m_apply_invalid (blocking is enforced independently via get_enable_slice_status() / find_next_sliceable_plate_for_slice_all()).

Slice-path integration

  • update_background_process(): invoke sync_flow_ratio_zero_notification() after the blanket close_notification_of_type(ValidateError); fold its return value into UPDATE_BACKGROUND_PROCESS_INVALID / UPDATE_BACKGROUND_PROCESS_RESTART to plug the Preview-tab-switch / reslice path.
  • start_next_slice(): new independent-dimension check; on slice_all it posts Finished to skip the current plate, on single-plate it sets process_completed_with_error. Comment emphasizes "two blockers must be parallel ifs, never else-if".
  • EVT_GLVIEWTOOLBAR_PREVIEW: switched from "directly fire slice_all" to "first check can_slice() + temp_mixing + flow_ratio_zero; if blocked, sync notifications and switch to Preview view".
  • guard_before_slice_plate() / guard_before_slice_all(): appended sync calls.
  • find_next_sliceable_plate_for_slice_all(): added !is_plate_blocked_by_flow_ratio_zero() condition.
  • EVT_FILAMENT_USAGE_CHANGED and end of load_files(): appended sync.
  • MainFrame::get_enable_slice_status(), GLCanvas3D::_render_imgui_select_plate_toolbar: added blocking check; grey out slice button / show SLICE_FAILED.

Related fixes (bundled — worth a separate glance)

  • PrintBase.hpp + Snapmaker_Orca.cpp: renamed STRING_EXCEPT_FILAMENTS_DIFFERENT_TEMPSTRING_EXCEPT_FILAMENTS_MIXING_TEMP (clearer semantics), added STRING_EXCEPT_FLOW_RATIO_ZERO = 6.
  • GCodeReader.cpp: parse_file_raw_internal() returns false when fopen fails, preventing fread(NULL) from triggering a CRT invalid-parameter crash.
  • Plater::load_gcode(): pre-check for missing file — gives an accurate error instead of the misleading "does not contain valid G-code".
  • 3MF load validity-error dedup: skip the filament_flow_ratio entry (already surfaced more precisely by the flow_ratio_zero banner); don't pop an empty notification when all entries are skipped.
  • History commits on this branch also include: per-filament high/low breakdown for temp-mixing notifications, on-demand checks replacing the cached flag, and unified plate-error gating.

Localization

  • localization/i18n/zh_CN/Snapmaker_Orca_zh_CN.po: added flow_ratio_zero error strings (Chinese only; other languages will be synced by CI / run_gettext later).

Reviewer Focus

Please prioritize the following (ordered by risk):

1. Parity between check_flow_ratio_zero and check_filament_temp_mixing (most important)

Both must use exactly the same definition of "actually-used slot", otherwise you get inconsistent states ("temp mixing blocks but flow_ratio doesn't", or vice versa). Please verify item-by-item:

  • collection order across plate config / object config / volume config
  • uses_default_extruder flag + global extruder resolution
  • boundaries of always_collect (wipe_tower / support / support_interface) vs default_keys (wall / sparse_infill / solid_infill)
  • expansion of ModelVolume::get_extruders()

Forward-looking note: these two near-identical blocks should be factored into a shared helper. PR #627 (cold plate) already does this refactor — merge order between the two PRs needs to be coordinated to avoid conflicts.

2. The <= 0.0 comparison

The code deliberately uses ratio <= 0.0 instead of == 0.0, with the comment "to dodge floating-point comparison traps". But what's the smallest legal positive value of filament_flow_ratio in the UI? Could a tiny positive value (e.g. 1e-6) be mis-classified as an offender due to FP precision? Please confirm against the actual preset range (recommend either strict <= 0.0 or explicit == 0.0).

3. Correctness of close-then-push notification

  • sync_flow_ratio_zero_notification() relies on the flow_ratio_zero_last_error_text cache for exact-text close. Please check:
    • The curr_plate == nullptr early-return does not clear the cache — could there be a cross-plate-switch scenario where a stale notification lingers?
    • update_background_process() requires the sync to run after the blanket close — is this ordering satisfied at every call site? Especially EVT_FILAMENT_USAGE_CHANGED and the end of load_files().
  • When both flow_ratio_zero and filament_temp_mixing notifications are active, can two ValidateErrors of the same type but different text clobber each other?

4. Dual-blocker ordering in start_next_slice()

The new flow_ratio_zero check sits after temp_mixing as an independent if (not else-if). Please confirm:

  • When both fire, both syncs run (user sees two notifications) — is that intended?
  • On the slice_all path, either blocker posts Finished to skip the current plate; does find_next_sliceable_plate_for_slice_all() correctly advance to the next legal plate?

5. Behavior change in EVT_GLVIEWTOOLBAR_PREVIEW

Before: when has_sliceable_plate_for_slice_all() was true, the handler switched to 3D Editor and posted SLICE_ALLauto-triggering a slice.
After: it checks blockers first; if blocked, switches to Preview view without slicing.
Please confirm this behavior change doesn't break the existing "click Preview to auto-slice_all" workflow — in particular, is the non-blocking auto-slice behavior preserved? (From the diff, the entire non-blocking path appears to have been removed — please confirm this is intentional.)

6. Enum / persistence impact

  • STRING_EXCEPT_FILAMENTS_DIFFERENT_TEMPSTRING_EXCEPT_FILAMENTS_MIXING_TEMP: search the whole repo to confirm no missed call sites (CLI, 3MF serialization, Sentry reporting, etc.).
  • New STRING_EXCEPT_FLOW_RATIO_ZERO = 6: does it conflict with how StringExceptionType is persisted in 3MF; is opening an old .3mf project safe?

7. Regression risk from bundled fixes

  • GCodeReader::parse_file_raw_internal() NULL-FILE* defense: will Sentry crashes that previously fired on this path disappear?
  • load_gcode() missing-file check: does it cover Unicode paths / network paths under wxFileExists?
  • 3MF validity skipping filament_flow_ratio: confirm this is the only key the flow_ratio_zero banner takes over; are there other keys that should also be skipped?

8. i18n coverage

  • This PR only updates the zh_CN .po — the other 20 languages are not synced. The flow_ratio_zero copy will fall back to English in non-Chinese locales. Is that acceptable, or should we wait for update-translation.yml to auto-sync?

Test Plan

  • Set any filament's filament_flow_ratio to 0 → that plate's slice button greys out; ValidateError lists [n] PresetName
  • Set filament_flow_ratio to a tiny positive value (e.g. 0.001) → should not be blocked (verifies the <= 0.0 boundary)
  • Only one slot has ratio=0 but is unused → should not be blocked (verifies only used slots are checked)
  • Only one slot has ratio=0 and is actually used by an object → blocked, and the slot is named precisely
  • Both flow_ratio_zero and temp mixing triggered → two ValidateError notifications coexist without clobbering
  • Slice All: plate A blocked / plate B compatible → auto-advance to plate B
  • Reslice / Preview-tab switch: a blocked plate must not silently start slicing
  • 3MF load: a project containing filament_flow_ratio=0 → only the flow_ratio_zero banner shows; no duplicate "Invalid values found in the 3mf" notification
  • Loading a non-existent G-code file → "file does not exist" dialog, no crash
  • Verify the Chinese copy renders correctly; switching to English / other locales at least doesn't crash (fallback acceptable)

🤖 Generated with Claude Code

iesteem and others added 8 commits July 15, 2026 19:11
- Remove has_sliceable_plate_for_slice_all() hijack in Preview tab switch
  that triggered unintended "slice all" instead of switching to preview
- Add m_filament_temp_blocked flag to PartPlate so can_slice() reflects
  filament temp mixing state, consistent with m_apply_invalid for
  object-outside errors
- Let sync_filament_temp_mixing_notification() manage its own flag,
  independent of the background validation system
- Simplify EVT_GLVIEWTOOLBAR_PREVIEW to use can_slice() as unified gate
  for both error types

Downstream effects: red exclamation icon on plate thumbnails, disabled
slice/export buttons, and blocked auto-slice on preview switch now work
uniformly for both object-outside and filament-temp-mixing errors.
…xing

Replace the per-plate cached m_filament_temp_blocked flag with on-demand
is_plate_blocked_by_filament_temp_mixing() checks in the rendering and
preview-switch paths. This eliminates staleness risks identified during
code review where non-current plates could retain stale blocked state
after filament changes, undo/redo, or plate switching during slicing.

Changes:
- GLCanvas3D: add on-demand check for red exclamation on plate thumbnails
- Plater: add on-demand check in EVT_GLVIEWTOOLBAR_PREVIEW alongside
  can_slice(), keep sync_filament_temp_mixing_notification() for
  notification freshness
- PartPlate: revert cached flag; can_slice() unchanged

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…xing

Merge duplicate key lists, rename used_slots for clarity, and group logic
into scoped blocks. No semantic change.
…EPT_FILAMENTS_MIXING_TEMP

Better reflects that the check is about high/low temperature material mixing,
not just "different" temperatures.
Add per-filament high/low temperature breakdown to the filament temp
mixing warning/error notifications so users can see exactly which slots
are in conflict, both for single-plate and slice-all modes.

- Plater::check_filament_temp_mixing now exposes a FilamentTempMixingDetail
  (high/low 1-based slot lists) via a new overload
- Notification text becomes dynamic; sync_filament_temp_mixing_notification
  caches the exact pushed strings to work around NotificationManager's
  exact-text close matching
- confirm_filament_temp_mixing_before_slice / _before_slice_all use the
  same breakdown in their modal dialogs
- Safe translation helper tr_u8() avoids the dangling-pointer trap in
  I18N::translate_utf8() that crashed in non-English locales
- Add zh_CN translations for the new strings

Also fix a separate crash: GCodeReader::parse_file_raw_internal no longer
dereferences a NULL FILE* when fopen fails (e.g. loading a non-existent
gcode file at startup), and Plater::load_gcode now checks wxFileExists
up front to give a precise "does not exist" error instead of the vague
"does not contain valid G-code".
When a used filament's flow_ratio is 0, the slicer previously failed
downstream with a misleading "bed beyond limits" error. Now it is
caught up-front: the slice button greys out and a red banner names
the offending filament(s) in "[n] PresetName" form, semicolon-
separated for multiple offenders.

Mirrors the existing filament_temp_mixing validator structure:
- New STRING_EXCEPT_FLOW_RATIO_ZERO enum value.
- New FlowRatioZeroDetail + 4 methods on Plater.
- check_flow_ratio_zero() reuses the shared slot-collection helpers
  and reads filament_flow_ratio from each used preset.
- sync_flow_ratio_zero_notification() caches the last pushed text
  for exact-text close/repush, and runs AFTER the ValidateError
  blanket-close in update_background_process so it isn't killed.
- 11 sync trigger points + MainFrame gate + Slice All skip rule.
- zh_CN translations for the 3 new banner strings.
…d preview indicator

- Feed sync_flow_ratio_zero_notification() return value into
  UPDATE_BACKGROUND_PROCESS_INVALID so the reslice path (Preview
  Tab switch -> do_reslice -> update_background_process) is also
  blocked, not just the explicit slice button path.
- Filter filament_flow_ratio out of the 3MF validity loop so the
  legacy BBL3MFInfo popup does not duplicate the dedicated
  flow_ratio_zero ValidateError banner.
- Add is_plate_blocked_by_flow_ratio_zero to the GLCanvas3D
  per-plate toolbar gate so the Preview tab shows the red
  SLICE_FAILED indicator on blocked plates, matching the
  filament_temp_mixing behavior.
@iesteem iesteem changed the title Fix flow ratio feat: block slicing when filament flow ratio is 0 (with per-filament breakdown) Jul 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant