feat(mixed-filament): phase 2 hardening — ratio cap, recipe dedupe, cancel-aware rematch - #617
Merged
Kenshin627 merged 12 commits intoJul 27, 2026
Conversation
…safety hardening Add max_component_percent through the color-match pipeline (build_best_color_match_recipe, batch_match_model_colors, recommend_best_filament_combo) to cap any single filament's share of a mix: - RECOMMENDED: [0%, 70%] — product spec enforces no dominant component - MANUAL: [15%, 100%] — near-pure allowed; over-70% surfaces as a post-match advisory via new check_manual_recipe_ratio(), listing all over-threshold IDs Rename "CMYW" → "Full Spectrum"; add canonical preset constant (kFullSpectrumPresetName) and auto-assign it to slots 1-4 after batch match so the combobox shows the preset name instead of F1-F4. Harden cleanup_unused_filaments_after_batch_match: promote the redundant_physical descending invariant from assert() to a runtime check (assert is compiled out under NDEBUG), with a per-deletion fallback that keeps colours correct when violated. Fix dangling reference in extract_model_colors — the ternary bound a temporary MixedFilamentManager to a reference (use-after-scope UB); now a raw pointer with null-check at the virtual-lookup site only. Robustness: clamp mix_b_percent to [0,100], defer 64-color warning until after build_ui, static_cast cleanup, null-guard preset_bundle at startup. Harness review fixes (dev-guidelines): validate max_component_percent range in build_best_color_match_recipe, replace residual C-style cast, document m_match_running as UI-thread-only.
Kenshin627
reviewed
Jul 24, 2026
| // Virtual mixed filament — look up its display_color. | ||
| // Early startup or rare call paths may have no preset_bundle; | ||
| // skip virtual-colour resolution then rather than dereference null. | ||
| if (pb == nullptr) { |
Collaborator
Author
There was a problem hiding this comment.
为什么不能直接"提到循环外"
pb 只在虚拟混合丝分支(idx >= filament_colours.size(),line 1334)里需要。物理颜色分支(line 1331-1333)完全不依赖 pb:
cpp
if (idx < filament_colours.size()) {
color_hex = filament_colours[idx]; // 物理颜色 — 不需要 pb
} else {
if (pb == nullptr) { continue; } // 虚拟颜色 — 需要 pb
...
}
如果把 if (pb == nullptr) 提到最外层循环并 continue/return,会把物理颜色也一起跳过——那是错的。所以这个 null 检查必须留在 else 分支里,它检查的是"这次访问需不需要 pb",不是"整个循环要不要跑"。
The object list's filament column still displayed old physical-slot extruder IDs after confirming a batch color match because the earlier on_filaments_change refresh ran before apply_batch_match_to_model did the actual extruder remapping. Root causes and fixes: 1. MixedFilamentBatchDialog::load_model_colors() was enumerating the extruder palette array instead of walking the model's actual painted extruder IDs via get_extruders(). This missed volume config-level extruder assignments (no MMU paint) and virtual mixed-filament IDs that were deduplicated against the physical palette. Rewrote to walk every MODEL_PART volume, look up each extruder's hex colour from the physical palette or the mixed-filament display_color table, and accumulate all matching extruder IDs per colour. 2. Recommended-mode confirm path (Plater.cpp) was losing pre-existing custom mixed filaments because set_num_filaments calls clear_custom_entries(). Fixed by snapshotting the old mixed list before the call, reloading custom entries from project_config afterwards to preserve stable_ids, and building an old→new virtual ID remap so on_filaments_change correctly translates existing painted mixed-IDs before apply_batch_match_to_model runs. 3. Added obj_list()->update_objects_list_filament_column() call after apply_batch_match_to_model completes so the object list reflects the post-remap extruder IDs.
…-match confirm - Per-row hover tooltip: localized color name + hex + TD (resolved by color family, not palette position — survives ΔE fallback reorder) - Row border wraps swatch + name together (was: name field only) - Cancel prompts discard confirmation only when a match result exists - Skip refresh on method re-select (wxMSW combobox quirk) - Consolidate Full Spectrum preset name into kFullSpectrumPresetName
…, UX polish - merge_duplicate_recipe_mappings: byte-identical non-pure recipes share one virtual slot - distinguish recommend_best_filament_combo cancel vs no-combo (error_code 2) - restore prior preview on failed re-match only when input unchanged - triple-loop wb bound respects max_component_percent - banners moved below mode row; canvas3D() -> get_view3D_canvas3D()
…l_colors pb is loop-invariant; the per-iteration null check stayed (correct — physical-colour path must not be skipped), but its warning fired once per virtual-painted face. Hoist the warning above the loop, leave the inner check as a silent continue.
fix: object list filament column not updating after batch color match
…safety hardening Add max_component_percent through the color-match pipeline (build_best_color_match_recipe, batch_match_model_colors, recommend_best_filament_combo) to cap any single filament's share of a mix: - RECOMMENDED: [0%, 70%] — product spec enforces no dominant component - MANUAL: [15%, 100%] — near-pure allowed; over-70% surfaces as a post-match advisory via new check_manual_recipe_ratio(), listing all over-threshold IDs Rename "CMYW" → "Full Spectrum"; add canonical preset constant (kFullSpectrumPresetName) and auto-assign it to slots 1-4 after batch match so the combobox shows the preset name instead of F1-F4. Harden cleanup_unused_filaments_after_batch_match: promote the redundant_physical descending invariant from assert() to a runtime check (assert is compiled out under NDEBUG), with a per-deletion fallback that keeps colours correct when violated. Fix dangling reference in extract_model_colors — the ternary bound a temporary MixedFilamentManager to a reference (use-after-scope UB); now a raw pointer with null-check at the virtual-lookup site only. Robustness: clamp mix_b_percent to [0,100], defer 64-color warning until after build_ui, static_cast cleanup, null-guard preset_bundle at startup. Harness review fixes (dev-guidelines): validate max_component_percent range in build_best_color_match_recipe, replace residual C-style cast, document m_match_running as UI-thread-only.
…-match confirm - Per-row hover tooltip: localized color name + hex + TD (resolved by color family, not palette position — survives ΔE fallback reorder) - Row border wraps swatch + name together (was: name field only) - Cancel prompts discard confirmation only when a match result exists - Skip refresh on method re-select (wxMSW combobox quirk) - Consolidate Full Spectrum preset name into kFullSpectrumPresetName
…, UX polish - merge_duplicate_recipe_mappings: byte-identical non-pure recipes share one virtual slot - distinguish recommend_best_filament_combo cancel vs no-combo (error_code 2) - restore prior preview on failed re-match only when input unchanged - triple-loop wb bound respects max_component_percent - banners moved below mode row; canvas3D() -> get_view3D_canvas3D()
…l_colors pb is loop-invariant; the per-iteration null check stayed (correct — physical-colour path must not be skipped), but its warning fired once per virtual-painted face. Hoist the warning above the loop, leave the inner check as a silent continue.
Add check_compatible through the recipe-search pipeline so manual mode can create cross-type mixes (PLA+PETG). RECOMMENDED keeps the same-type filter; the slice gate (has_incompatible_mixed_filament_in_use) still blocks them at slice time — widen in, strict out. Also: empty error_message on cancel (code 2 is a silent rollback), discard-confirm focus fix on wxMSW, banner spacing, RichMessageDialog for the no-model/<2-filament prompts.
All 4 remote commits had identical counterparts locally, so every conflict resolved as "Use HEAD" — no behavioural change from remote.
3 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Phase 2 hardening of the mixed-color batch-match flow. Builds on the phase-1
batch dialog with four areas of work: a per-component ratio cap, duplicate-
recipe deduplication, cancel-aware re-match, and UX polish.
What's new
Per-component ratio cap (
max_component_percent)Threaded through the whole match chain (
build_best_color_match_recipe→batch_match_model_colors→recommend_best_filament_combo), limiting anysingle filament's share of a mix:
post-match advisory via
check_manual_recipe_ratio(), listing allover-threshold filament IDs.
Duplicate-recipe deduplication (
merge_duplicate_recipe_mappings)Mappings whose non-pure recipes are byte-identical (same components + ratio +
gradient) now share one virtual slot instead of each allocating a duplicate
mixed-filament row. The survivor unions
source_extruder_idsandmerged_model_indices; runs after both ID-assignment phases so it keeps thefinal
target_filament_id. Pure recipes pass through untouched.Cancel-aware re-match
recommend_best_filament_comboreturns{}for both "no combo" and"cancelled" — disambiguated via a post-call
cancel_tokenre-check, routinga cancelled result (error_code 2) directly with no error banner and skipping
the Pass-2 match. On a failed/cancelled re-match, the prior preview is
restored only when user-facing input is unchanged (mode + manual selections).
"CMYW" → "Full Spectrum" rename
New canonical constant
kFullSpectrumPresetName; slots 1-4 auto-assigned thepreset after batch match so the combobox shows the preset name, not F1-F4.
Bug & safety fixes
extract_model_colors: ternary bound atemporary to a reference (use-after-scope). Now a raw pointer with null-check
at the virtual-lookup site; null warning logged once (was per-face).
cleanup_unused_filaments_after_batch_match:promoted from
assert()(compiled out underNDEBUG) to a runtime checkwith a per-deletion fallback that keeps colours correct on violation.
mix_b_percentclamped to[0,100]; 64-color warning deferred until afterbuild_ui();preset_bundlenull-guarded at startup.wbupper bound now respectsmax_component_percent.static_cast;m_match_runningdocumented UI-thread-only.UX polish
color family, not palette position).
canvas3D()→get_view3D_canvas3D()on the thumbnail render path.Tests
cmake --build build --target Snapmaker_Orca --config Releasepreset_bundleis null