From aee6db8e275b5a530aa32d4be6b63a22e4d53f1e Mon Sep 17 00:00:00 2001 From: sentientstardust Date: Fri, 8 May 2026 04:02:13 +0100 Subject: [PATCH] Make sure texture mapping zone sparse IDs are recognized in libslic3r internals --- src/libslic3r/GCode/ToolOrdering.cpp | 22 +++-- src/libslic3r/Print.cpp | 3 +- src/libslic3r/PrintApply.cpp | 3 +- src/libslic3r/PrintObject.cpp | 130 +++++++++++++++++++++------ src/libslic3r/PrintRegion.cpp | 15 +++- 5 files changed, 136 insertions(+), 37 deletions(-) diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index 9349d4ebee4..2696f24f1be 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -136,6 +136,8 @@ unsigned int LayerTools::resolve_filament_id(unsigned int filament_id_1based) co num_physical_filaments > 0 && texture_mapping_manager->is_texture_mapping_zone_id(filament_id_1based)) return texture_mapping_manager->resolve_zone_component(filament_id_1based, num_physical_filaments, layer_index); + if (num_physical_filaments > 0 && filament_id_1based > num_physical_filaments) + return 1; return filament_id_1based; } @@ -582,10 +584,14 @@ std::vector ToolOrdering::generate_first_layer_tool_order(const Pr for (auto layerm : target_layer->regions()) { const int raw_extruder_id = layerm->region().config().option("wall_filament")->getInt(); - const unsigned int resolved_extruder_id = raw_extruder_id <= 0 ? 0 : - print.texture_mapping_manager().resolve_zone_component(unsigned(raw_extruder_id), print.config().filament_colour.size(), int(target_layer->id())); - if (resolved_extruder_id == 0 || resolved_extruder_id > print.config().filament_colour.size()) + unsigned int resolved_extruder_id = raw_extruder_id <= 0 ? 0 : + print.texture_mapping_manager().resolve_zone_component(unsigned(raw_extruder_id), + print.config().filament_colour.size(), + int(target_layer->id())); + if (resolved_extruder_id == 0) continue; + if (resolved_extruder_id > print.config().filament_colour.size()) + resolved_extruder_id = 1; int extruder_id = int(resolved_extruder_id); for (auto expoly : layerm->raw_slices) { @@ -651,10 +657,14 @@ std::vector ToolOrdering::generate_first_layer_tool_order(const Pr for (auto layerm : target_layer->regions()) { const int raw_extruder_id = layerm->region().config().option("wall_filament")->getInt(); - const unsigned int resolved_extruder_id = raw_extruder_id <= 0 ? 0 : - object.print()->texture_mapping_manager().resolve_zone_component(unsigned(raw_extruder_id), object.print()->config().filament_colour.size(), int(target_layer->id())); - if (resolved_extruder_id == 0 || resolved_extruder_id > object.print()->config().filament_colour.size()) + unsigned int resolved_extruder_id = raw_extruder_id <= 0 ? 0 : + object.print()->texture_mapping_manager().resolve_zone_component(unsigned(raw_extruder_id), + object.print()->config().filament_colour.size(), + int(target_layer->id())); + if (resolved_extruder_id == 0) continue; + if (resolved_extruder_id > object.print()->config().filament_colour.size()) + resolved_extruder_id = 1; int extruder_id = int(resolved_extruder_id); for (auto expoly : layerm->raw_slices) { const double nozzle_diameter = object.print()->config().nozzle_diameter.get_at(0); diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 8d083905599..60a833e2847 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -92,7 +92,8 @@ static void append_used_physical_extruders_for_filament_id(const TextureMappingM return; } - append_physical(unsigned(filament_id)); + const unsigned int physical_id = unsigned(filament_id); + append_physical(physical_id <= num_physical ? physical_id : 1); } static std::array prime_tower_parse_hex_color_for_print(const std::string &hex) diff --git a/src/libslic3r/PrintApply.cpp b/src/libslic3r/PrintApply.cpp index 63b5354fbc6..e062d729944 100644 --- a/src/libslic3r/PrintApply.cpp +++ b/src/libslic3r/PrintApply.cpp @@ -1254,7 +1254,8 @@ static void append_used_filament_from_config_id(const TextureMappingManager return; } - append_physical(unsigned(filament_id)); + const unsigned int physical_id = unsigned(filament_id); + append_physical(physical_id <= num_physical_extruders ? physical_id : 1); } static void append_model_used_filaments_for_normalization(const Model &model, diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index c44f4a6d8c6..422739a9b5d 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -14,6 +14,7 @@ #include "Surface.hpp" #include "Slicing.hpp" #include "Tesselate.hpp" +#include "TextureMapping.hpp" #include "TriangleMeshSlicer.hpp" #include "Utils.hpp" #include "Fill/FillAdaptive.hpp" @@ -22,6 +23,7 @@ #include "format.hpp" #include "AABBTreeLines.hpp" +#include #include #include #include @@ -289,6 +291,68 @@ void PrintObject::_transform_hole_to_polyholes() } } +static std::vector physical_extruders_for_filament_id(const TextureMappingManager &texture_mgr, + int filament_id, + size_t num_physical, + const std::vector &filament_colours) +{ + std::vector out; + if (filament_id <= 0 || num_physical == 0) + return out; + + auto append_physical = [num_physical, &out](unsigned int physical_id) { + if (physical_id >= 1 && physical_id <= num_physical) + out.emplace_back(physical_id - 1); + }; + + const TextureMappingZone *zone = texture_mgr.zone_from_id(unsigned(filament_id)); + if (zone != nullptr) { + if (!zone->enabled || zone->deleted) + return out; + + std::vector colors = filament_colours; + colors.resize(num_physical, "#FFFFFF"); + std::vector component_ids = zone->is_image_texture() ? + TextureMappingManager::effective_texture_component_ids(*zone, num_physical, colors) : + TextureMappingManager::selected_component_ids(*zone, num_physical); + + for (unsigned int component_id : component_ids) + append_physical(component_id); + + if (out.empty()) + append_physical(texture_mgr.resolve_zone_component(unsigned(filament_id), num_physical, 0)); + } else { + const unsigned int physical_id = unsigned(filament_id); + append_physical(physical_id <= num_physical ? physical_id : 1); + } + + sort_remove_duplicates(out); + return out; +} + +template +static bool contains_any_physical_extruder(const Set &set, const std::vector &extruders) +{ + return std::any_of(extruders.begin(), extruders.end(), [&set](unsigned int extruder) { + return set.count(int(extruder)) > 0; + }); +} + +template +static bool contains_missing_physical_extruder(const Set &set, const std::vector &extruders) +{ + return std::any_of(extruders.begin(), extruders.end(), [&set](unsigned int extruder) { + return set.count(int(extruder)) == 0; + }); +} + +template +static void insert_physical_extruders(Set &set, const std::vector &extruders) +{ + for (unsigned int extruder : extruders) + set.insert(int(extruder)); +} + std::vector> PrintObject::detect_extruder_geometric_unprintables() const { int extruder_size = m_print->config().nozzle_diameter.size(); @@ -296,6 +360,12 @@ std::vector> PrintObject::detect_extruder_geometric_unprintables() return std::vector>(1, std::set()); std::vector> geometric_unprintables(extruder_size); // the container to return + const size_t num_physical_filaments = m_print->config().filament_colour.size(); + const TextureMappingManager &texture_mgr = m_print->texture_mapping_manager(); + const std::vector filament_colours = m_print->config().filament_colour.values; + auto resolve_physical_extruders = [&texture_mgr, num_physical_filaments, &filament_colours](int filament_id) { + return physical_extruders_for_filament_id(texture_mgr, filament_id, num_physical_filaments, filament_colours); + }; std::vector printable_height_per_extruder = m_print->config().extruder_printable_height.values; assert(printable_height_per_extruder.size() == extruder_size); @@ -309,18 +379,18 @@ std::vector> PrintObject::detect_extruder_geometric_unprintables() continue; for (auto layerm : layer->regions()) { auto region = layerm->region(); - int wall_filament = region.config().wall_filament; - int solid_infill_filament = region.config().solid_infill_filament; - int sparse_infill_filament = region.config().sparse_infill_filament; + const std::vector wall_filaments = resolve_physical_extruders(region.config().wall_filament); + const std::vector solid_infill_filaments = + resolve_physical_extruders(region.config().solid_infill_filament); + const std::vector sparse_infill_filaments = + resolve_physical_extruders(region.config().sparse_infill_filament); if (!layerm->fills.entities.empty()) { - if (solid_infill_filament > 0) - geometric_unprintables[extruder_id].insert(solid_infill_filament - 1); - if (sparse_infill_filament > 0) - geometric_unprintables[extruder_id].insert(sparse_infill_filament - 1); + insert_physical_extruders(geometric_unprintables[extruder_id], solid_infill_filaments); + insert_physical_extruders(geometric_unprintables[extruder_id], sparse_infill_filaments); } - if (!layerm->perimeters.entities.empty() && wall_filament > 0) - geometric_unprintables[extruder_id].insert(wall_filament - 1); + if (!layerm->perimeters.entities.empty()) + insert_physical_extruders(geometric_unprintables[extruder_id], wall_filaments); } } } @@ -340,26 +410,33 @@ std::vector> PrintObject::detect_extruder_geometric_unprintables() // check unprintbale filaments caused by printable area limit tbb::parallel_for(tbb::blocked_range(0, m_layers.size()), - [this, &tbb_geometric_unprintables, &unprintable_area_in_obj_coord, &unprintable_area_bbox](const tbb::blocked_range& range) { + [this, + &tbb_geometric_unprintables, + &unprintable_area_in_obj_coord, + &unprintable_area_bbox, + &resolve_physical_extruders](const tbb::blocked_range& range) { for (int j = range.begin(); j < range.end(); ++j) { auto layer = m_layers[j]; for (auto layerm : layer->regions()) { const auto& region = layerm->region(); - int wall_filament = region.config().wall_filament; - int solid_infill_filament = region.config().solid_infill_filament; - int sparse_infill_filament = region.config().sparse_infill_filament; + const std::vector wall_filaments = resolve_physical_extruders(region.config().wall_filament); + const std::vector solid_infill_filaments = + resolve_physical_extruders(region.config().solid_infill_filament); + const std::vector sparse_infill_filaments = + resolve_physical_extruders(region.config().sparse_infill_filament); std::optional fill_expolys; BoundingBox fill_bbox; std::optional wall_expolys; BoundingBox wall_bbox; for (size_t idx = 0; idx < unprintable_area_in_obj_coord.size(); ++idx) { - bool do_infill_filament_detect = (solid_infill_filament > 0 && tbb_geometric_unprintables[idx].count(solid_infill_filament - 1) == 0) || - (sparse_infill_filament > 0 && tbb_geometric_unprintables[idx].count(sparse_infill_filament-1) == 0); + bool do_infill_filament_detect = + contains_missing_physical_extruder(tbb_geometric_unprintables[idx], solid_infill_filaments) || + contains_missing_physical_extruder(tbb_geometric_unprintables[idx], sparse_infill_filaments); bool infill_unprintable = !layerm->fills.entities.empty() && - ((solid_infill_filament > 0 && tbb_geometric_unprintables[idx].count(solid_infill_filament - 1) > 0) || - (sparse_infill_filament > 0 && tbb_geometric_unprintables[idx].count(sparse_infill_filament - 1) > 0)); + (contains_any_physical_extruder(tbb_geometric_unprintables[idx], solid_infill_filaments) || + contains_any_physical_extruder(tbb_geometric_unprintables[idx], sparse_infill_filaments)); if (!layerm->fills.entities.empty() && do_infill_filament_detect) { if (!fill_expolys) { @@ -368,19 +445,17 @@ std::vector> PrintObject::detect_extruder_geometric_unprintables() } if (fill_bbox.overlap(unprintable_area_bbox[idx]) && !intersection(*fill_expolys, unprintable_area_in_obj_coord[idx]).empty()) { - if (solid_infill_filament > 0) - tbb_geometric_unprintables[idx].insert(solid_infill_filament - 1); - if (sparse_infill_filament > 0) - tbb_geometric_unprintables[idx].insert(sparse_infill_filament - 1); + insert_physical_extruders(tbb_geometric_unprintables[idx], solid_infill_filaments); + insert_physical_extruders(tbb_geometric_unprintables[idx], sparse_infill_filaments); infill_unprintable = true; } } - bool do_wall_filament_detect = wall_filament > 0 && tbb_geometric_unprintables[idx].count(wall_filament - 1) == 0; + bool do_wall_filament_detect = contains_missing_physical_extruder(tbb_geometric_unprintables[idx], wall_filaments); if (!layerm->perimeters.entities.empty() && do_wall_filament_detect) { // if infill is unprintable, no need to check wall since wall contour surrounds infill contour if (infill_unprintable) { - tbb_geometric_unprintables[idx].insert(wall_filament - 1); + insert_physical_extruders(tbb_geometric_unprintables[idx], wall_filaments); continue; } @@ -395,7 +470,7 @@ std::vector> PrintObject::detect_extruder_geometric_unprintables() if (wall_bbox.overlap(unprintable_area_bbox[idx]) && !intersection(*wall_expolys, unprintable_area_in_obj_coord[idx]).empty()) { - tbb_geometric_unprintables[idx].insert(wall_filament - 1); + insert_physical_extruders(tbb_geometric_unprintables[idx], wall_filaments); } } } @@ -3477,11 +3552,16 @@ std::vector PrintObject::object_extruders() const region.collect_object_printing_extruders(*this->print(), extruders); const ModelObject* mo = this->model_object(); + const size_t num_physical = this->print()->config().filament_colour.size(); for (const ModelVolume* mv : mo->volumes) { std::vector volume_extruders = mv->get_extruders(); for (int extruder : volume_extruders) { assert(extruder > 0); - extruders.push_back(extruder - 1); + append(extruders, + physical_extruders_for_filament_id(this->print()->texture_mapping_manager(), + extruder, + num_physical, + this->print()->config().filament_colour.values)); } } sort_remove_duplicates(extruders); diff --git a/src/libslic3r/PrintRegion.cpp b/src/libslic3r/PrintRegion.cpp index 7e8bef2dbd9..a5879403277 100644 --- a/src/libslic3r/PrintRegion.cpp +++ b/src/libslic3r/PrintRegion.cpp @@ -63,7 +63,8 @@ static void append_used_physical_extruders_for_filament_id(const Print return; } - append_physical(unsigned(filament_id)); + const unsigned int physical_id = unsigned(filament_id); + append_physical(physical_id <= num_physical ? physical_id : 1); } // 1-based extruder identifier for this region and role. @@ -153,9 +154,15 @@ void PrintRegion::collect_object_printing_extruders(const Print &print, std::vec #ifndef NDEBUG // BBS auto num_extruders = int(print.config().filament_diameter.size()); - assert(this->config().wall_filament <= num_extruders || print.texture_mapping_manager().is_texture_mapping_zone_id(this->config().wall_filament)); - assert(this->config().sparse_infill_filament <= num_extruders || print.texture_mapping_manager().is_texture_mapping_zone_id(this->config().sparse_infill_filament)); - assert(this->config().solid_infill_filament <= num_extruders || print.texture_mapping_manager().is_texture_mapping_zone_id(this->config().solid_infill_filament)); + auto can_resolve_filament_id = [num_extruders, &print](int filament_id) { + return filament_id >= 0 && + (filament_id <= num_extruders || + print.texture_mapping_manager().is_texture_mapping_zone_id(unsigned(filament_id)) || + num_extruders > 0); + }; + assert(can_resolve_filament_id(this->config().wall_filament)); + assert(can_resolve_filament_id(this->config().sparse_infill_filament)); + assert(can_resolve_filament_id(this->config().solid_infill_filament)); #endif if (this->config().wall_loops.value > 0 || print.has_brim()) append_used_physical_extruders_for_filament_id(print, this->config().wall_filament.value, object_extruders);