init work to integrate OrcaSlicer-FullSpectrum fork Integrations up to commit b3c41fda41.

- libslic3r: vendor FilamentMixer; MixedFilamentManager (auto-gen, resolve,
    serialize; manual-pattern / gradient / pointillism); 19 new PrintConfig
    keys; PresetBundle owns the canonical manager with 3MF + AppConfig
    roundtrip and AMS-safe strip+restore; Print owns the slicing-time copy
    with PrintApply auto-regen on color change; TriangleSelector::
    shift_states_above + filament-id remap; inset_idx propagation through
    ExtrusionPath/Loop/MultiPath copy/assign.
  - Slicing: virtual filament IDs in painted regions (same-physical channels
    collapse when mixed_filament_region_collapse is on); ByObject
    collect_filament_data expands mixed slots; pair-cadence + whole-object +
    3+component Local-Z plan generators; LocalZOrderOptimizer utility.
  - GCode + ToolOrdering: LayerTools resolves virtual IDs through wall /
    infill / sparse / solid queries; SameLayerPointillisme in process_layer
    (uniform-segment + grouped per-perimeter-index splitters); WipeTower2
    Local-Z reservation + sub-layer G-code emission; per-layer infill
    filament override.
  - PartPlate: get_extruders* expand virtual slots into physical components;
    CLI path rebuilds a local manager from full_config.
  - GUI: five widget files extracted from FS Plater.cpp (~5000 LOC) —
    MixedMixPreview, MixedGradientSelector + WeightsDialog,
    MixedFilamentColorMapPanel, MixedFilamentColorMatchDialog (ΔE₀₀ recipe
    search), MixedFilamentConfigPanel; Sidebar Mixed Filaments panel
    (drag-reorder, enable/delete, Add Gradient/Pattern/Color); Tab exposure
    of mixed-filament / dithering / per-layer infill-override settings +
    ConfigManipulation visibility and slot-validation rules;
    BBLMixedFilamentBroken / BBLSingleExtruderMixedFilamentRisk
    notifications + slice gate; WipeTowerDialog edits physical P×P
    sub-matrix; bounds-safe extruder_id guards in 3DScene / GLCanvas3D /
    GLGizmoMmuSegmentation; change_filament merge guard and
    on_filaments_delete is_mixed_before_delete propagation.
  - Tests: 4 Catch2 tests for 3MF roundtrip (auto/custom persistence,
    PresetBundle string path, total_filaments stability); full-pipeline
    slice E2E deferred — TODO in file.

Co-authored-by: Rad <radugheorghiu96@gmail.com>
Co-authored-by: Justin Hayes <justinh@rahb.ca>
Co-authored-by: Calogero Guagenti <calogeroguagenti@gmail.com>
Co-authored-by: xSil3nt <ahmedshazin21@gmail.com>
Co-authored-by: ratdoux <62392831+ratdoux@users.noreply.github.com>

Update TriangleSelector.cpp

Co-Authored-By: Rad <radugheorghiu96@gmail.com>
Co-Authored-By: Justin Hayes <justinh@rahb.ca>
Co-Authored-By: Calogero Guagenti <calogeroguagenti@gmail.com>
Co-Authored-By: xSil3nt <ahmedshazin21@gmail.com>
Co-Authored-By: ratdoux <62392831+ratdoux@users.noreply.github.com>
This commit is contained in:
SoftFever
2026-06-01 09:24:53 -03:00
committed by Ian Bassi
co-authored by Rad Justin Hayes Calogero Guagenti xSil3nt ratdoux
parent 7a0c149701
commit 0e0e34c8b4
68 changed files with 18988 additions and 267 deletions
+186 -7
View File
@@ -1104,6 +1104,57 @@ static PrintObjectRegions* generate_print_object_regions(
return out.release();
}
// ---- Mixed-filament helpers used in Print::apply ----------------------------------------
static inline void append_unique_painted_extruder(std::vector<unsigned int> &painting_extruders,
unsigned int extruder_id,
size_t num_physical_extruders)
{
if (extruder_id < 1 || extruder_id > num_physical_extruders)
return;
if (std::find(painting_extruders.begin(), painting_extruders.end(), extruder_id) == painting_extruders.end())
painting_extruders.emplace_back(extruder_id);
}
// For a virtual (mixed) ID, expand to all physical component IDs it may resolve to.
// This pre-creates regions for every physical tool the mixed row can use so that
// apply_mm_segmentation can collapse mixed channels onto the correct region.
static void append_mixed_component_extruders(const MixedFilamentManager &mixed_mgr,
unsigned int state_id,
size_t num_physical_extruders,
std::vector<unsigned int> &painting_extruders)
{
if (state_id <= num_physical_extruders)
return;
const MixedFilament *mixed_row = mixed_mgr.mixed_filament_from_id(state_id, num_physical_extruders);
if (mixed_row == nullptr || !mixed_row->enabled)
return;
append_unique_painted_extruder(painting_extruders, mixed_row->component_a, num_physical_extruders);
append_unique_painted_extruder(painting_extruders, mixed_row->component_b, num_physical_extruders);
for (char token : mixed_row->gradient_component_ids) {
if (token < '1' || token > '9')
continue;
append_unique_painted_extruder(painting_extruders, unsigned(token - '0'), num_physical_extruders);
}
for (char token : mixed_row->manual_pattern) {
unsigned int extruder_id = 0;
if (token == '1')
extruder_id = mixed_row->component_a;
else if (token == '2')
extruder_id = mixed_row->component_b;
else if (token >= '3' && token <= '9')
extruder_id = unsigned(token - '0');
append_unique_painted_extruder(painting_extruders, extruder_id, num_physical_extruders);
}
}
// -----------------------------------------------------------------------------------------
Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_config, bool extruder_applied)
{
#ifdef _DEBUG
@@ -1116,6 +1167,54 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
new_full_config.option("print_settings_id", true);
new_full_config.option("filament_settings_id", true);
new_full_config.option("printer_settings_id", true);
// Ensure mixed-filament and dithering keys are present so in-session updates are detected.
new_full_config.option("mixed_filament_gradient_mode", true);
new_full_config.option("mixed_color_layer_height_a", true);
new_full_config.option("mixed_color_layer_height_b", true);
new_full_config.option("mixed_filament_height_lower_bound", true);
new_full_config.option("mixed_filament_height_upper_bound", true);
new_full_config.option("mixed_filament_advanced_dithering", true);
new_full_config.option("mixed_filament_component_bias_enabled", true);
new_full_config.option("mixed_filament_surface_indentation", true);
new_full_config.option("mixed_filament_region_collapse", true);
new_full_config.option("mixed_filament_definitions", true);
new_full_config.option("dithering_z_step_size", true);
new_full_config.option("dithering_local_z_mode", true);
new_full_config.option("dithering_local_z_whole_objects", true);
new_full_config.option("dithering_local_z_direct_multicolor", true);
new_full_config.option("dithering_step_painted_zones_only", true);
// Materialize the same keys on m_config so print_diff sees no phantom changes on cold start.
m_config.option("mixed_filament_gradient_mode", true);
m_config.option("mixed_color_layer_height_a", true);
m_config.option("mixed_color_layer_height_b", true);
m_config.option("mixed_filament_height_lower_bound", true);
m_config.option("mixed_filament_height_upper_bound", true);
m_config.option("mixed_filament_advanced_dithering", true);
m_config.option("mixed_filament_component_bias_enabled", true);
m_config.option("mixed_filament_surface_indentation", true);
m_config.option("mixed_filament_region_collapse", true);
m_config.option("mixed_filament_definitions", true);
m_config.option("dithering_z_step_size", true);
m_config.option("dithering_local_z_mode", true);
m_config.option("dithering_local_z_whole_objects", true);
m_config.option("dithering_local_z_direct_multicolor", true);
m_config.option("dithering_step_painted_zones_only", true);
// Materialize the same keys on m_default_object_config for symmetry.
m_default_object_config.option("mixed_filament_gradient_mode", true);
m_default_object_config.option("mixed_color_layer_height_a", true);
m_default_object_config.option("mixed_color_layer_height_b", true);
m_default_object_config.option("mixed_filament_height_lower_bound", true);
m_default_object_config.option("mixed_filament_height_upper_bound", true);
m_default_object_config.option("mixed_filament_advanced_dithering", true);
m_default_object_config.option("mixed_filament_component_bias_enabled", true);
m_default_object_config.option("mixed_filament_surface_indentation", true);
m_default_object_config.option("mixed_filament_region_collapse", true);
m_default_object_config.option("mixed_filament_definitions", true);
m_default_object_config.option("dithering_z_step_size", true);
m_default_object_config.option("dithering_local_z_mode", true);
m_default_object_config.option("dithering_local_z_whole_objects", true);
m_default_object_config.option("dithering_local_z_direct_multicolor", true);
m_default_object_config.option("dithering_step_painted_zones_only", true);
// BBS
std::vector <unsigned int> used_filaments = this->extruders(true);
@@ -1281,6 +1380,77 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
}
}
// Rebuild the mixed (virtual) filament manager from physical colours and user-defined
// custom entries. This must happen after m_config is up-to-date so filament_colour
// reflects the correct physical palette.
{
int mixed_gradient_mode = 0;
float mixed_height_lower = 0.04f;
float mixed_height_upper = 0.16f;
bool mixed_advanced_dither = false;
float mixed_surface_indentation = 0.f;
std::string mixed_custom_definitions;
if (new_full_config.has("mixed_filament_gradient_mode")) {
if (const ConfigOptionBool *opt = new_full_config.option<ConfigOptionBool>("mixed_filament_gradient_mode"))
mixed_gradient_mode = opt->value ? 1 : 0;
else
mixed_gradient_mode = new_full_config.opt_int("mixed_filament_gradient_mode");
}
if (new_full_config.has("mixed_filament_height_lower_bound"))
mixed_height_lower = float(new_full_config.opt_float("mixed_filament_height_lower_bound"));
if (new_full_config.has("mixed_filament_height_upper_bound"))
mixed_height_upper = float(new_full_config.opt_float("mixed_filament_height_upper_bound"));
if (new_full_config.has("mixed_filament_advanced_dithering")) {
if (const ConfigOptionBool *opt = new_full_config.option<ConfigOptionBool>("mixed_filament_advanced_dithering"))
mixed_advanced_dither = opt->value;
else
mixed_advanced_dither = (new_full_config.opt_int("mixed_filament_advanced_dithering") != 0);
}
if (new_full_config.has("mixed_filament_surface_indentation"))
mixed_surface_indentation = float(new_full_config.opt_float("mixed_filament_surface_indentation"));
if (new_full_config.has("mixed_filament_definitions"))
mixed_custom_definitions = new_full_config.opt_string("mixed_filament_definitions");
mixed_gradient_mode = std::clamp(mixed_gradient_mode, 0, 1);
mixed_height_lower = std::max(0.01f, mixed_height_lower);
mixed_height_upper = std::max(mixed_height_lower, mixed_height_upper);
mixed_surface_indentation = std::clamp(mixed_surface_indentation, -2.f, 2.f);
BOOST_LOG_TRIVIAL(info) << "Print::apply mixed settings"
<< ", gradient_mode=" << mixed_gradient_mode
<< ", lower=" << mixed_height_lower
<< ", upper=" << mixed_height_upper
<< ", advanced_dither=" << (mixed_advanced_dither ? 1 : 0)
<< ", surface_indentation=" << mixed_surface_indentation
<< ", custom_definitions_len=" << mixed_custom_definitions.size()
<< ", physical_extruders=" << num_extruders;
// Regenerate mixed (virtual) filaments from physical filament colours and
// re-apply user custom mixed definitions.
std::vector<std::string> physical_filament_colors = m_config.filament_colour.values;
physical_filament_colors.resize(num_extruders, "#26A69A");
m_mixed_filament_mgr.clear_custom_entries();
m_mixed_filament_mgr.auto_generate(physical_filament_colors);
m_mixed_filament_mgr.load_custom_entries(mixed_custom_definitions, physical_filament_colors);
m_mixed_filament_mgr.apply_gradient_settings(mixed_gradient_mode,
mixed_height_lower,
mixed_height_upper,
mixed_advanced_dither);
size_t mixed_custom_count = 0;
for (const auto &mf : m_mixed_filament_mgr.mixed_filaments())
if (mf.custom)
++mixed_custom_count;
BOOST_LOG_TRIVIAL(info) << "Print::apply mixed manager state"
<< ", mixed_total=" << m_mixed_filament_mgr.mixed_filaments().size()
<< ", mixed_enabled=" << m_mixed_filament_mgr.enabled_count()
<< ", mixed_custom=" << mixed_custom_count;
}
// Total filaments = physical extruders + enabled mixed (virtual) filaments.
// Used for extruder ID clamping so that virtual IDs are accepted.
const size_t num_total_filaments = m_mixed_filament_mgr.total_filaments(num_extruders);
ModelObjectStatusDB model_object_status_db;
// 1) Synchronize model objects.
@@ -1468,7 +1638,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
if (object_config_changed)
model_object.config.assign_config(model_object_new.config);
if (! object_diff.empty() || object_config_changed || num_extruders_changed ) {
PrintObjectConfig new_config = PrintObject::object_config_from_model_object(m_default_object_config, model_object, num_extruders );
PrintObjectConfig new_config = PrintObject::object_config_from_model_object(m_default_object_config, model_object, num_total_filaments);
for (const PrintObjectStatus &print_object_status : print_object_status_db.get_range(model_object)) {
t_config_option_keys diff = print_object_status.print_object->config().diff(new_config);
if (! diff.empty()) {
@@ -1534,10 +1704,10 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
// Generate a list of trafos and XY offsets for instances of a ModelObject
// Producing the config for PrintObject on demand, caching it at print_object_last.
const PrintObject *print_object_last = nullptr;
auto print_object_apply_config = [this, &print_object_last, model_object, num_extruders ](PrintObject *print_object) {
auto print_object_apply_config = [this, &print_object_last, model_object, num_total_filaments](PrintObject *print_object) {
print_object->config_apply(print_object_last ?
print_object_last->config() :
PrintObject::object_config_from_model_object(m_default_object_config, *model_object, num_extruders ));
PrintObject::object_config_from_model_object(m_default_object_config, *model_object, num_total_filaments));
print_object_last = print_object;
};
if (old.empty()) {
@@ -1682,9 +1852,18 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
}
for (size_t state_idx = static_cast<size_t>(EnforcerBlockerType::Extruder1); state_idx < used_facet_states.size(); ++state_idx) {
if (used_facet_states[state_idx])
painting_extruders.emplace_back(state_idx);
if (!used_facet_states[state_idx])
continue;
if (state_idx <= num_total_filaments) {
painting_extruders.emplace_back(static_cast<unsigned int>(state_idx));
append_mixed_component_extruders(m_mixed_filament_mgr,
static_cast<unsigned int>(state_idx),
num_extruders,
painting_extruders);
}
}
std::sort(painting_extruders.begin(), painting_extruders.end());
painting_extruders.erase(std::unique(painting_extruders.begin(), painting_extruders.end()), painting_extruders.end());
}
if (model_object_status.print_object_regions_status == ModelObjectStatus::PrintObjectRegionsStatus::Valid) {
// Verify that the trafo for regions & volume bounding boxes thus for regions is still applicable.
@@ -1702,7 +1881,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
verify_update_print_object_regions(
print_object.model_object()->volumes,
m_default_region_config,
num_extruders,
num_total_filaments,
*print_object_regions,
[it_print_object, it_print_object_end, &update_apply_status](const PrintRegionConfig &old_config, const PrintRegionConfig &new_config, const t_config_option_keys &diff_keys) {
for (auto it = it_print_object; it != it_print_object_end; ++it)
@@ -1727,7 +1906,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
LayerRanges(print_object.model_object()->layer_config_ranges),
m_default_region_config,
model_object_status.print_instances.front().trafo,
num_extruders ,
num_total_filaments,
print_object.is_mm_painted() ? 0.f : float(print_object.config().xy_contour_compensation.value),
painting_extruders,
print_object.is_fuzzy_skin_painted());