Update from FS at b3c41fda4.

Slicing
  - align merge_segmented_layers shape with FS apply_mm_segmentation
    (size = num_facets_states, loop from 0, no -1 shift); painted mixed
    regions were previously attributed to filament_id-1 of intent.
    apply_fuzzy_skin_segmentation reads channel 1;
    apply_mixed_surface_indentation uses segmentation_channel_filament_id
  - port apply_mixed_surface_indentation, apply_mixed_component_surface_offsets,
    apply_mixed_region_surface_offsets, apply_surface_emboss_mixed_region_override,
    plus surface_emboss_mixed_* debug subsystem
  - refactor apply_mm_segmentation (by-value MM, bias_mode, surface-type-
    preserving intersection, region normalization, post-MM dump); hoist MM
    segmentation into slice_volumes so mixed apply_* flow can mutate it
  - restore clear_local_z_plan() invalidation hooks
    (PrintObject.cpp:805/1264/1286)

  GCode
  - add LayerTools::preserve_extruder_order, honored by collect_extruders,
    both reorder_extruders overloads, and
    reorder_filaments_for_minimum_flush_volume; helpers
    append_unique_preserve_order / remove_duplicates_preserve_order
  - wire MixedFilamentManager::ordered_perimeter_extruders for grouped
    manual-pattern walls; set preserve_extruder_order when >= 2
  - mixed-aware support: layer_height set for support-only layers,
    ExtrusionRole-based has_support/has_interface with erMixed short-
    circuit, support_filament / support_interface_filament routed through
    resolve_mixed

  Print
  - materialize mixed_filament_pointillism_{pixel_size,line_gap} in
    PrintApply's option-tracking block so in-session edits diff correctly

  GUI
  - Tab::on_value_change: dithering_local_z_mode cascading clears, 17-key
    project_config sync, update_mixed_filament_panel(false) on
    mixed_filament_component_bias_enabled change
  - GUI_Factories: physical_filaments_count, ui_ordered_filament_ids,
    filament_menu_item_name; filaments_count includes enabled mixed
    virtuals; right-click 'Change filament' submenus iterate UI-ordered IDs

  Tests
  - sentinel asserting MultiMaterialSegmentation uses FS-aligned shape
    (39 -> 40)
This commit is contained in:
SoftFever
2026-04-29 19:22:29 +08:00
parent 9c8caf121e
commit 103cf247e5
10 changed files with 1516 additions and 184 deletions

View File

@@ -6,6 +6,9 @@
#include "libslic3r/Model.hpp"
#include "libslic3r/Slicing.hpp"
#include <boost/filesystem.hpp>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
@@ -130,3 +133,57 @@ TEST_CASE("[review-fixes] mixed/dithering option keys exist in PrintConfig",
REQUIRE(print_config_def.get(k) != nullptr);
}
}
TEST_CASE("[review-fixes] clear_local_z_plan called from clear_layers", "[review-fixes][mixed-filament]")
{
// Sentinel: ensure the source contains the 3 invalidation hooks the
// FullSpectrum verification report flagged as missing. This is a
// smoke-test against the source so we can detect future regressions
// without depending on a full slicing-pipeline harness.
namespace fs = boost::filesystem;
const fs::path repo = fs::path(__FILE__).parent_path().parent_path().parent_path();
const fs::path src = repo / "src" / "libslic3r" / "PrintObject.cpp";
REQUIRE(fs::exists(src));
std::ifstream in(src.string());
std::stringstream buf; buf << in.rdbuf();
const std::string body = buf.str();
const auto count_substr = [&](const std::string &needle) {
size_t n = 0, pos = 0;
while ((pos = body.find(needle, pos)) != std::string::npos) { ++n; ++pos; }
return n;
};
// Three FS-mandated call sites: clear_layers, invalidate_step(posSlice),
// invalidate_all_steps. Plus the one already-present site inside
// build_local_z_plan(). PrintObject.cpp itself has 3 (4 once the
// backport is complete).
REQUIRE(count_substr("this->clear_local_z_plan()") >= 3);
}
TEST_CASE("[review-fixes] merge_segmented_layers preserves channel 0", "[review-fixes][mixed-filament]")
{
// Sentinel: ensure merge_segmented_layers uses the FS shape
// (output sized num_facets_states, channel 0 = default), not the
// pre-FS-a11b70e3a shape (output sized num_facets_states - 1,
// channel 0 dropped). The FS-verbatim apply_mm_segmentation in
// PrintObjectSlice.cpp expects channel 0 to be present; mismatching
// shapes silently shifts every painted region's filament_id by -1
// (e.g. paint with mixed slot 4 -> applied as physical filament 3).
namespace fs = boost::filesystem;
const fs::path repo = fs::path(__FILE__).parent_path().parent_path().parent_path();
const fs::path src = repo / "src" / "libslic3r" / "MultiMaterialSegmentation.cpp";
REQUIRE(fs::exists(src));
std::ifstream in(src.string());
std::stringstream buf; buf << in.rdbuf();
const std::string body = buf.str();
// Producer must NOT subtract one from num_facets_states when sizing the output.
REQUIRE(body.find("num_facets_states - 1") == std::string::npos);
// Producer must NOT shift indexing back by one when writing into the output.
REQUIRE(body.find("[extruder_id - 1]") == std::string::npos);
// Loop must include channel 0 (extruder_id starts at 0, not 1).
REQUIRE(body.find("for (size_t extruder_id = 0; extruder_id < num_facets_states") != std::string::npos);
}