mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-09 18:27:00 +00:00
Collapse same-color mixed filament regions across painted areas
Resolve ordinary mixed-filament painted regions to their effective physical filament on each layer so adjacent same-color zones can merge into one continuous area instead of being sliced as separate islands. Add a global "Collapse same-color mixed regions" option, enabled by default, and automatically turn it off when Local Z dithering is enabled while still allowing manual re-enable for experimental use.
This commit is contained in:
@@ -1321,6 +1321,43 @@ unsigned int MixedFilamentManager::resolve_perimeter(unsigned int filament_id,
|
|||||||
return resolve(filament_id, num_physical, layer_index, layer_print_z, layer_height, force_height_weighted);
|
return resolve(filament_id, num_physical, layer_index, layer_print_z, layer_height, force_height_weighted);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int MixedFilamentManager::effective_painted_region_filament_id(unsigned int filament_id,
|
||||||
|
size_t num_physical,
|
||||||
|
int layer_index,
|
||||||
|
float layer_print_z,
|
||||||
|
float layer_height,
|
||||||
|
float layer_height_a,
|
||||||
|
float layer_height_b,
|
||||||
|
float base_layer_height) const
|
||||||
|
{
|
||||||
|
const int mixed_idx = mixed_index_from_filament_id(filament_id, num_physical);
|
||||||
|
if (mixed_idx < 0)
|
||||||
|
return filament_id;
|
||||||
|
|
||||||
|
const MixedFilament &mf = m_mixed[size_t(mixed_idx)];
|
||||||
|
if (mf.distribution_mode == int(MixedFilament::SameLayerPointillisme))
|
||||||
|
return filament_id;
|
||||||
|
|
||||||
|
const std::string normalized_pattern = normalize_manual_pattern(mf.manual_pattern);
|
||||||
|
if (normalized_pattern.find(',') != std::string::npos)
|
||||||
|
return filament_id;
|
||||||
|
|
||||||
|
const bool is_custom_mixed = mf.custom;
|
||||||
|
if (!is_custom_mixed && (layer_height_a > 0.f || layer_height_b > 0.f)) {
|
||||||
|
const float safe_base = std::max<float>(0.01f, base_layer_height);
|
||||||
|
const int ratio_a = std::max(1, int(std::lround((layer_height_a > 0.f ? layer_height_a : safe_base) / safe_base)));
|
||||||
|
const int ratio_b = std::max(1, int(std::lround((layer_height_b > 0.f ? layer_height_b : safe_base) / safe_base)));
|
||||||
|
const int cycle = ratio_a + ratio_b;
|
||||||
|
|
||||||
|
if (cycle > 0) {
|
||||||
|
const int pos = ((layer_index % cycle) + cycle) % cycle;
|
||||||
|
return pos < ratio_a ? mf.component_a : mf.component_b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolve(filament_id, num_physical, layer_index, layer_print_z, layer_height);
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<unsigned int> MixedFilamentManager::ordered_perimeter_extruders(unsigned int filament_id,
|
std::vector<unsigned int> MixedFilamentManager::ordered_perimeter_extruders(unsigned int filament_id,
|
||||||
size_t num_physical,
|
size_t num_physical,
|
||||||
int layer_index,
|
int layer_index,
|
||||||
|
|||||||
@@ -179,6 +179,18 @@ public:
|
|||||||
float layer_print_z = 0.f,
|
float layer_print_z = 0.f,
|
||||||
float layer_height = 0.f,
|
float layer_height = 0.f,
|
||||||
bool force_height_weighted = false) const;
|
bool force_height_weighted = false) const;
|
||||||
|
// Resolve the filament ID that should own painted regions on this layer.
|
||||||
|
// Modes that require virtual identity later in G-code generation keep the
|
||||||
|
// original mixed ID; ordinary mixed rows collapse to the current physical
|
||||||
|
// extruder so adjacent same-tool regions can merge.
|
||||||
|
unsigned int effective_painted_region_filament_id(unsigned int filament_id,
|
||||||
|
size_t num_physical,
|
||||||
|
int layer_index,
|
||||||
|
float layer_print_z = 0.f,
|
||||||
|
float layer_height = 0.f,
|
||||||
|
float layer_height_a = 0.f,
|
||||||
|
float layer_height_b = 0.f,
|
||||||
|
float base_layer_height = 0.2f) const;
|
||||||
std::vector<unsigned int> ordered_perimeter_extruders(unsigned int filament_id,
|
std::vector<unsigned int> ordered_perimeter_extruders(unsigned int filament_id,
|
||||||
size_t num_physical,
|
size_t num_physical,
|
||||||
int layer_index,
|
int layer_index,
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ static std::vector<std::string> s_project_options {
|
|||||||
"mixed_filament_height_upper_bound",
|
"mixed_filament_height_upper_bound",
|
||||||
"mixed_filament_advanced_dithering",
|
"mixed_filament_advanced_dithering",
|
||||||
"mixed_filament_surface_indentation",
|
"mixed_filament_surface_indentation",
|
||||||
|
"mixed_filament_region_collapse",
|
||||||
"mixed_filament_definitions",
|
"mixed_filament_definitions",
|
||||||
"mixed_color_layer_height_a",
|
"mixed_color_layer_height_a",
|
||||||
"mixed_color_layer_height_b",
|
"mixed_color_layer_height_b",
|
||||||
|
|||||||
@@ -297,6 +297,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
|
|||||||
|| opt_key == "mixed_filament_height_upper_bound"
|
|| opt_key == "mixed_filament_height_upper_bound"
|
||||||
|| opt_key == "mixed_filament_advanced_dithering"
|
|| opt_key == "mixed_filament_advanced_dithering"
|
||||||
|| opt_key == "mixed_filament_surface_indentation"
|
|| opt_key == "mixed_filament_surface_indentation"
|
||||||
|
|| opt_key == "mixed_filament_region_collapse"
|
||||||
|| opt_key == "mixed_filament_definitions"
|
|| opt_key == "mixed_filament_definitions"
|
||||||
// Spiral Vase forces different kind of slicing than the normal model:
|
// Spiral Vase forces different kind of slicing than the normal model:
|
||||||
// In Spiral Vase mode, holes are closed and only the largest area contour is kept at each layer.
|
// In Spiral Vase mode, holes are closed and only the largest area contour is kept at each layer.
|
||||||
|
|||||||
@@ -1112,18 +1112,22 @@ static inline void append_unique_painted_extruder(std::vector<unsigned int> &pai
|
|||||||
painting_extruders.emplace_back(extruder_id);
|
painting_extruders.emplace_back(extruder_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void append_same_layer_component_extruders(const MixedFilamentManager &mixed_mgr,
|
static void append_mixed_component_extruders(const MixedFilamentManager &mixed_mgr,
|
||||||
unsigned int state_id,
|
unsigned int state_id,
|
||||||
size_t num_physical_extruders,
|
size_t num_physical_extruders,
|
||||||
std::vector<unsigned int> &painting_extruders)
|
std::vector<unsigned int> &painting_extruders)
|
||||||
{
|
{
|
||||||
if (state_id <= num_physical_extruders)
|
if (state_id <= num_physical_extruders)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const MixedFilament *mixed_row = mixed_mgr.mixed_filament_from_id(state_id, num_physical_extruders);
|
const MixedFilament *mixed_row = mixed_mgr.mixed_filament_from_id(state_id, num_physical_extruders);
|
||||||
if (mixed_row == nullptr || !mixed_row->enabled || mixed_row->distribution_mode != int(MixedFilament::SameLayerPointillisme))
|
if (mixed_row == nullptr || !mixed_row->enabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Pre-create painted target regions for every physical filament a mixed row
|
||||||
|
// may resolve to. apply_mm_segmentation can then collapse ordinary mixed
|
||||||
|
// channels onto the active physical tool for a layer without losing the
|
||||||
|
// destination region.
|
||||||
append_unique_painted_extruder(painting_extruders, mixed_row->component_a, num_physical_extruders);
|
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);
|
append_unique_painted_extruder(painting_extruders, mixed_row->component_b, num_physical_extruders);
|
||||||
|
|
||||||
@@ -1177,6 +1181,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
|||||||
new_full_config.option("mixed_filament_pointillism_pixel_size", true);
|
new_full_config.option("mixed_filament_pointillism_pixel_size", true);
|
||||||
new_full_config.option("mixed_filament_pointillism_line_gap", true);
|
new_full_config.option("mixed_filament_pointillism_line_gap", true);
|
||||||
new_full_config.option("mixed_filament_surface_indentation", 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("mixed_filament_definitions", true);
|
||||||
m_config.option("dithering_z_step_size", true);
|
m_config.option("dithering_z_step_size", true);
|
||||||
m_config.option("dithering_local_z_mode", true);
|
m_config.option("dithering_local_z_mode", true);
|
||||||
@@ -1188,6 +1193,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
|||||||
m_config.option("mixed_filament_pointillism_pixel_size", true);
|
m_config.option("mixed_filament_pointillism_pixel_size", true);
|
||||||
m_config.option("mixed_filament_pointillism_line_gap", true);
|
m_config.option("mixed_filament_pointillism_line_gap", true);
|
||||||
m_config.option("mixed_filament_surface_indentation", 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("mixed_filament_definitions", true);
|
||||||
m_default_object_config.option("dithering_z_step_size", 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_mode", true);
|
||||||
@@ -1199,6 +1205,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
|||||||
m_default_object_config.option("mixed_filament_pointillism_pixel_size", true);
|
m_default_object_config.option("mixed_filament_pointillism_pixel_size", true);
|
||||||
m_default_object_config.option("mixed_filament_pointillism_line_gap", true);
|
m_default_object_config.option("mixed_filament_pointillism_line_gap", true);
|
||||||
m_default_object_config.option("mixed_filament_surface_indentation", 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("mixed_filament_definitions", true);
|
||||||
// BBS
|
// BBS
|
||||||
int used_filaments = this->extruders(true).size();
|
int used_filaments = this->extruders(true).size();
|
||||||
@@ -1772,10 +1779,10 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
|||||||
continue;
|
continue;
|
||||||
if (state_idx <= num_total_filaments) {
|
if (state_idx <= num_total_filaments) {
|
||||||
painting_extruders.emplace_back(static_cast<unsigned int>(state_idx));
|
painting_extruders.emplace_back(static_cast<unsigned int>(state_idx));
|
||||||
append_same_layer_component_extruders(m_mixed_filament_mgr,
|
append_mixed_component_extruders(m_mixed_filament_mgr,
|
||||||
static_cast<unsigned int>(state_idx),
|
static_cast<unsigned int>(state_idx),
|
||||||
num_extruders,
|
num_extruders,
|
||||||
painting_extruders);
|
painting_extruders);
|
||||||
} else
|
} else
|
||||||
++dropped_painted_states;
|
++dropped_painted_states;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4244,6 +4244,15 @@ void PrintConfigDef::init_fff_params()
|
|||||||
def->mode = comAdvanced;
|
def->mode = comAdvanced;
|
||||||
def->set_default_value(new ConfigOptionFloat(0.0));
|
def->set_default_value(new ConfigOptionFloat(0.0));
|
||||||
|
|
||||||
|
def = this->add("mixed_filament_region_collapse", coBool);
|
||||||
|
def->label = L("Collapse same-color mixed regions");
|
||||||
|
def->category = L("Others");
|
||||||
|
def->tooltip = L("Merge ordinary mixed-filament painted regions into a single area when they resolve to the same physical filament on a layer.\n\n"
|
||||||
|
"This improves continuity for adjacent same-color areas. Local Z dithering turns this off automatically when enabled, but you may turn it back on manually.\n\n"
|
||||||
|
"Experimental with Local Z dithering.");
|
||||||
|
def->mode = comAdvanced;
|
||||||
|
def->set_default_value(new ConfigOptionBool(true));
|
||||||
|
|
||||||
def = this->add("mixed_filament_definitions", coString);
|
def = this->add("mixed_filament_definitions", coString);
|
||||||
def->label = L("Mixed filament custom definitions");
|
def->label = L("Mixed filament custom definitions");
|
||||||
def->tooltip = L("Serialized custom mixed filament rows.\n\n"
|
def->tooltip = L("Serialized custom mixed filament rows.\n\n"
|
||||||
|
|||||||
@@ -1363,6 +1363,7 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE(
|
|||||||
((ConfigOptionFloat, mixed_filament_pointillism_pixel_size))
|
((ConfigOptionFloat, mixed_filament_pointillism_pixel_size))
|
||||||
((ConfigOptionFloat, mixed_filament_pointillism_line_gap))
|
((ConfigOptionFloat, mixed_filament_pointillism_line_gap))
|
||||||
((ConfigOptionFloat, mixed_filament_surface_indentation))
|
((ConfigOptionFloat, mixed_filament_surface_indentation))
|
||||||
|
((ConfigOptionBool, mixed_filament_region_collapse))
|
||||||
((ConfigOptionString, mixed_filament_definitions))
|
((ConfigOptionString, mixed_filament_definitions))
|
||||||
((ConfigOptionFloat, dithering_z_step_size))
|
((ConfigOptionFloat, dithering_z_step_size))
|
||||||
((ConfigOptionBool, dithering_local_z_mode))
|
((ConfigOptionBool, dithering_local_z_mode))
|
||||||
|
|||||||
@@ -950,6 +950,7 @@ bool PrintObject::invalidate_state_by_config_options(
|
|||||||
|| opt_key == "dithering_z_step_size"
|
|| opt_key == "dithering_z_step_size"
|
||||||
|| opt_key == "dithering_local_z_mode"
|
|| opt_key == "dithering_local_z_mode"
|
||||||
|| opt_key == "dithering_step_painted_zones_only"
|
|| opt_key == "dithering_step_painted_zones_only"
|
||||||
|
|| opt_key == "mixed_filament_region_collapse"
|
||||||
|| opt_key == "mmu_segmented_region_max_width"
|
|| opt_key == "mmu_segmented_region_max_width"
|
||||||
|| opt_key == "mmu_segmented_region_interlocking_depth"
|
|| opt_key == "mmu_segmented_region_interlocking_depth"
|
||||||
|| opt_key == "raft_layers"
|
|| opt_key == "raft_layers"
|
||||||
@@ -973,6 +974,7 @@ bool PrintObject::invalidate_state_by_config_options(
|
|||||||
|| opt_key == "mixed_filament_height_upper_bound"
|
|| opt_key == "mixed_filament_height_upper_bound"
|
||||||
|| opt_key == "mixed_filament_advanced_dithering"
|
|| opt_key == "mixed_filament_advanced_dithering"
|
||||||
|| opt_key == "mixed_filament_surface_indentation"
|
|| opt_key == "mixed_filament_surface_indentation"
|
||||||
|
|| opt_key == "mixed_filament_region_collapse"
|
||||||
|| opt_key == "mixed_filament_definitions") {
|
|| opt_key == "mixed_filament_definitions") {
|
||||||
// Mixed filament gradient controls affect layer cadence and virtual
|
// Mixed filament gradient controls affect layer cadence and virtual
|
||||||
// tool distribution, so force a re-slice prompt like other
|
// tool distribution, so force a re-slice prompt like other
|
||||||
|
|||||||
@@ -2947,9 +2947,21 @@ template<typename ThrowOnCancel>
|
|||||||
static inline void apply_mm_segmentation(PrintObject &print_object, std::vector<std::vector<ExPolygons>> segmentation, ThrowOnCancel throw_on_cancel)
|
static inline void apply_mm_segmentation(PrintObject &print_object, std::vector<std::vector<ExPolygons>> segmentation, ThrowOnCancel throw_on_cancel)
|
||||||
{
|
{
|
||||||
assert(segmentation.size() == print_object.layer_count());
|
assert(segmentation.size() == print_object.layer_count());
|
||||||
|
const PrintConfig &print_cfg = print_object.print()->config();
|
||||||
|
const DynamicPrintConfig &full_cfg = print_object.print()->full_print_config();
|
||||||
|
const size_t num_physical = print_cfg.filament_diameter.size();
|
||||||
|
const coordf_t preferred_a = float_from_full_config(full_cfg, "mixed_color_layer_height_a",
|
||||||
|
coordf_t(print_cfg.mixed_color_layer_height_a.value));
|
||||||
|
const coordf_t preferred_b = float_from_full_config(full_cfg, "mixed_color_layer_height_b",
|
||||||
|
coordf_t(print_cfg.mixed_color_layer_height_b.value));
|
||||||
|
const coordf_t base_height = std::max<coordf_t>(0.01f, coordf_t(print_object.config().layer_height.value));
|
||||||
|
const bool collapse_mixed_regions =
|
||||||
|
bool_from_full_config(full_cfg, "mixed_filament_region_collapse", print_cfg.mixed_filament_region_collapse.value);
|
||||||
|
const MixedFilamentManager &mixed_mgr = print_object.print()->mixed_filament_manager();
|
||||||
|
|
||||||
tbb::parallel_for(
|
tbb::parallel_for(
|
||||||
tbb::blocked_range<size_t>(0, segmentation.size(), std::max(segmentation.size() / 128, size_t(1))),
|
tbb::blocked_range<size_t>(0, segmentation.size(), std::max(segmentation.size() / 128, size_t(1))),
|
||||||
[&print_object, &segmentation, throw_on_cancel](const tbb::blocked_range<size_t> &range) {
|
[&print_object, &segmentation, &mixed_mgr, num_physical, preferred_a, preferred_b, base_height, collapse_mixed_regions, throw_on_cancel](const tbb::blocked_range<size_t> &range) {
|
||||||
const auto &layer_ranges = print_object.shared_regions()->layer_ranges;
|
const auto &layer_ranges = print_object.shared_regions()->layer_ranges;
|
||||||
double z = print_object.get_layer(int(range.begin()))->slice_z;
|
double z = print_object.get_layer(int(range.begin()))->slice_z;
|
||||||
auto it_layer_range = layer_range_first(layer_ranges, z);
|
auto it_layer_range = layer_range_first(layer_ranges, z);
|
||||||
@@ -2982,7 +2994,20 @@ static inline void apply_mm_segmentation(PrintObject &print_object, std::vector<
|
|||||||
size_t missing_target_regions = 0;
|
size_t missing_target_regions = 0;
|
||||||
std::vector<int> missing_target_extruders;
|
std::vector<int> missing_target_extruders;
|
||||||
for (size_t extruder_id = 0; extruder_id < num_extruders; ++ extruder_id) {
|
for (size_t extruder_id = 0; extruder_id < num_extruders; ++ extruder_id) {
|
||||||
ByExtruder ®ion = by_extruder[extruder_id];
|
const unsigned int channel_id = unsigned(extruder_id + 1);
|
||||||
|
const unsigned int effective_filament_id = collapse_mixed_regions ?
|
||||||
|
mixed_mgr.effective_painted_region_filament_id(channel_id,
|
||||||
|
num_physical,
|
||||||
|
int(layer_id),
|
||||||
|
float(layer.print_z),
|
||||||
|
float(layer.height),
|
||||||
|
float(preferred_a),
|
||||||
|
float(preferred_b),
|
||||||
|
float(base_height)) :
|
||||||
|
channel_id;
|
||||||
|
const size_t effective_idx =
|
||||||
|
effective_filament_id >= 1 && effective_filament_id <= num_extruders ? size_t(effective_filament_id - 1) : extruder_id;
|
||||||
|
ByExtruder ®ion = by_extruder[effective_idx];
|
||||||
append(region.expolygons, std::move(segmentation[layer_id][extruder_id]));
|
append(region.expolygons, std::move(segmentation[layer_id][extruder_id]));
|
||||||
if (! region.expolygons.empty()) {
|
if (! region.expolygons.empty()) {
|
||||||
region.bbox = get_extents(region.expolygons);
|
region.bbox = get_extents(region.expolygons);
|
||||||
|
|||||||
@@ -1491,6 +1491,21 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value)
|
|||||||
update_wiping_button_visibility();
|
update_wiping_button_visibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (opt_key == "dithering_local_z_mode" &&
|
||||||
|
boost::any_cast<bool>(value) &&
|
||||||
|
(!m_config->has("mixed_filament_region_collapse") ||
|
||||||
|
m_config->option("mixed_filament_region_collapse") == nullptr ||
|
||||||
|
m_config->opt_bool("mixed_filament_region_collapse"))) {
|
||||||
|
change_opt_value(*m_config, "mixed_filament_region_collapse", boost::any(false));
|
||||||
|
if (m_type == Preset::TYPE_PRINT) {
|
||||||
|
DynamicPrintConfig &project_cfg = wxGetApp().preset_bundle->project_config;
|
||||||
|
project_cfg.set_key_value("mixed_filament_region_collapse", new ConfigOptionBool(false));
|
||||||
|
}
|
||||||
|
if (Field *field = this->get_field("mixed_filament_region_collapse"))
|
||||||
|
field->set_value(boost::any(false), false);
|
||||||
|
update_dirty();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (opt_key == "single_extruder_multi_material" ){
|
if (opt_key == "single_extruder_multi_material" ){
|
||||||
const auto bSEMM = m_config->opt_bool("single_extruder_multi_material");
|
const auto bSEMM = m_config->opt_bool("single_extruder_multi_material");
|
||||||
@@ -1791,6 +1806,7 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value)
|
|||||||
opt_key == "mixed_filament_pointillism_pixel_size" ||
|
opt_key == "mixed_filament_pointillism_pixel_size" ||
|
||||||
opt_key == "mixed_filament_pointillism_line_gap" ||
|
opt_key == "mixed_filament_pointillism_line_gap" ||
|
||||||
opt_key == "mixed_filament_surface_indentation" ||
|
opt_key == "mixed_filament_surface_indentation" ||
|
||||||
|
opt_key == "mixed_filament_region_collapse" ||
|
||||||
opt_key == "dithering_z_step_size" ||
|
opt_key == "dithering_z_step_size" ||
|
||||||
opt_key == "dithering_local_z_mode" ||
|
opt_key == "dithering_local_z_mode" ||
|
||||||
opt_key == "dithering_step_painted_zones_only" ||
|
opt_key == "dithering_step_painted_zones_only" ||
|
||||||
@@ -2528,6 +2544,7 @@ optgroup->append_single_option_line("skirt_loops", "others_settings_skirt#loops"
|
|||||||
optgroup->append_single_option_line("mixed_filament_pointillism_pixel_size");
|
optgroup->append_single_option_line("mixed_filament_pointillism_pixel_size");
|
||||||
optgroup->append_single_option_line("mixed_filament_pointillism_line_gap");
|
optgroup->append_single_option_line("mixed_filament_pointillism_line_gap");
|
||||||
optgroup->append_single_option_line("mixed_filament_surface_indentation");
|
optgroup->append_single_option_line("mixed_filament_surface_indentation");
|
||||||
|
optgroup->append_single_option_line("mixed_filament_region_collapse");
|
||||||
optgroup->append_single_option_line("dithering_z_step_size");
|
optgroup->append_single_option_line("dithering_z_step_size");
|
||||||
optgroup->append_single_option_line("dithering_local_z_mode");
|
optgroup->append_single_option_line("dithering_local_z_mode");
|
||||||
optgroup->append_single_option_line("dithering_step_painted_zones_only");
|
optgroup->append_single_option_line("dithering_step_painted_zones_only");
|
||||||
|
|||||||
@@ -221,6 +221,41 @@ TEST_CASE("Mixed filament perimeter resolver uses grouped manual patterns by ins
|
|||||||
CHECK(ordered_layer1[1] == 1);
|
CHECK(ordered_layer1[1] == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Mixed filament painted-region resolver collapses ordinary mixed rows to the active physical extruder", "[MixedFilament]")
|
||||||
|
{
|
||||||
|
const std::vector<std::string> colors = {"#FF0000", "#00FF00"};
|
||||||
|
|
||||||
|
MixedFilamentManager mgr;
|
||||||
|
mgr.add_custom_filament(1, 2, 50, colors);
|
||||||
|
REQUIRE(mgr.mixed_filaments().size() == 1);
|
||||||
|
|
||||||
|
MixedFilament &row = mgr.mixed_filaments().front();
|
||||||
|
row.ratio_a = 1;
|
||||||
|
row.ratio_b = 1;
|
||||||
|
row.manual_pattern.clear();
|
||||||
|
row.distribution_mode = int(MixedFilament::Simple);
|
||||||
|
|
||||||
|
CHECK(mgr.effective_painted_region_filament_id(3, 2, 0) == 1);
|
||||||
|
CHECK(mgr.effective_painted_region_filament_id(3, 2, 1) == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Mixed filament painted-region resolver preserves virtual channels for grouped and same-layer modes", "[MixedFilament]")
|
||||||
|
{
|
||||||
|
const std::vector<std::string> colors = {"#00FFFF", "#FF00FF"};
|
||||||
|
|
||||||
|
MixedFilamentManager mgr;
|
||||||
|
mgr.add_custom_filament(1, 2, 50, colors);
|
||||||
|
REQUIRE(mgr.mixed_filaments().size() == 1);
|
||||||
|
|
||||||
|
MixedFilament &row = mgr.mixed_filaments().front();
|
||||||
|
row.manual_pattern = MixedFilamentManager::normalize_manual_pattern("12,21");
|
||||||
|
CHECK(mgr.effective_painted_region_filament_id(3, 2, 0) == 3);
|
||||||
|
|
||||||
|
row.manual_pattern.clear();
|
||||||
|
row.distribution_mode = int(MixedFilament::SameLayerPointillisme);
|
||||||
|
CHECK(mgr.effective_painted_region_filament_id(3, 2, 0) == 3);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("ExtrusionPath copies preserve inset index", "[MixedFilament]")
|
TEST_CASE("ExtrusionPath copies preserve inset index", "[MixedFilament]")
|
||||||
{
|
{
|
||||||
ExtrusionPath src(erPerimeter);
|
ExtrusionPath src(erPerimeter);
|
||||||
|
|||||||
Reference in New Issue
Block a user