From 8a19cf9d642e7c4d1eba9f0ef8191a8e1691ae3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Tue, 27 Apr 2021 00:37:49 +0200 Subject: [PATCH] Extended support of MMU segmentation backed for more than three colors. Serialization and deserialization in TriangleSelector were extended to support up to 16 materials (3 unused states left for possible later extension). These changes also affect the encoding of data from custom supports and seams, but it is backward compatible with the previous encoding. And for custom supports and seams, it is produced exactly the same data encoding as before. --- src/libslic3r/MultiMaterialSegmentation.cpp | 31 +++++++------- src/libslic3r/PrintObject.cpp | 3 +- src/libslic3r/TriangleSelector.cpp | 47 ++++++++++++++------- 3 files changed, 50 insertions(+), 31 deletions(-) diff --git a/src/libslic3r/MultiMaterialSegmentation.cpp b/src/libslic3r/MultiMaterialSegmentation.cpp index c3f2fed13d..aa25361083 100644 --- a/src/libslic3r/MultiMaterialSegmentation.cpp +++ b/src/libslic3r/MultiMaterialSegmentation.cpp @@ -1121,13 +1121,13 @@ static void cut_segmented_layers(const ConstLayerPtrsAdaptor layers, std::vector // Returns MMU segmentation of top and bottom layers based on painting in MMU segmentation gizmo static inline std::vector> mmu_segmentation_top_and_bottom_layers(const PrintObject &print_object) { + const size_t num_extruders = print_object.print()->config().nozzle_diameter.size(); const ConstLayerPtrsAdaptor layers = print_object.layers(); - std::vector> triangles_by_color(3); - triangles_by_color.assign(3, std::vector(layers.size())); + std::vector> triangles_by_color(num_extruders); + triangles_by_color.assign(num_extruders, std::vector(layers.size())); for (const ModelVolume *mv : print_object.model_object()->volumes) { - for (const auto ¶ms : {std::make_pair(EnforcerBlockerType::NONE, 0), std::make_pair(EnforcerBlockerType::ENFORCER, 1), - std::make_pair(EnforcerBlockerType::BLOCKER, 2)}) { - const indexed_triangle_set custom_facets = mv->mmu_segmentation_facets.get_facets(*mv, params.first); + for (size_t extruder_idx = 0; extruder_idx < num_extruders; ++extruder_idx) { + const indexed_triangle_set custom_facets = mv->mmu_segmentation_facets.get_facets(*mv, EnforcerBlockerType(extruder_idx)); if (!mv->is_model_part() || custom_facets.indices.empty()) continue; @@ -1168,7 +1168,7 @@ static inline std::vector> mmu_segmentation_top_and_bott for (auto layer_it = first_layer; (layer_it != (last_layer + 1) && layer_it != layers.end()); ++layer_it) { size_t layer_idx = layer_it - layers.begin(); - triangles_by_color[params.second][layer_idx].emplace_back(triangle); + triangles_by_color[extruder_idx][layer_idx].emplace_back(triangle); } } } @@ -1234,10 +1234,10 @@ static inline std::vector> mmu_segmentation_top_and_bott } }); // end of parallel_for - std::vector> triangles_by_color_bottom(3); - std::vector> triangles_by_color_top(3); - triangles_by_color_bottom.assign(3, std::vector(layers.size())); - triangles_by_color_top.assign(3, std::vector(layers.size())); + std::vector> triangles_by_color_bottom(num_extruders); + std::vector> triangles_by_color_top(num_extruders); + triangles_by_color_bottom.assign(num_extruders, std::vector(layers.size())); + triangles_by_color_top.assign(num_extruders, std::vector(layers.size())); for (size_t layer_idx = 0; layer_idx < print_object.layers().size(); ++layer_idx) { BOOST_LOG_TRIVIAL(debug) << "MMU segmentation of top layer: " << layer_idx; @@ -1306,8 +1306,8 @@ static inline std::vector> mmu_segmentation_top_and_bott } } - std::vector> triangles_by_color_merged(3); - triangles_by_color_merged.assign(3, std::vector(layers.size())); + std::vector> triangles_by_color_merged(num_extruders); + triangles_by_color_merged.assign(num_extruders, std::vector(layers.size())); for (size_t layer_idx = 0; layer_idx < layers.size(); ++layer_idx) { for (size_t color_idx = 0; color_idx < triangles_by_color_merged.size(); ++color_idx) { auto &self = triangles_by_color_merged[color_idx][layer_idx]; @@ -1367,8 +1367,9 @@ std::vector>> multi_material_segmentati } for (const ModelVolume *mv : print_object.model_object()->volumes) { - for (const auto ¶ms : {std::make_pair(EnforcerBlockerType::ENFORCER, 1), std::make_pair(EnforcerBlockerType::BLOCKER, 2)}) { - const indexed_triangle_set custom_facets = mv->mmu_segmentation_facets.get_facets(*mv, params.first); + const size_t num_extruders = print_object.print()->config().nozzle_diameter.size(); + for (size_t extruder_idx = 1; extruder_idx < num_extruders; ++extruder_idx) { + const indexed_triangle_set custom_facets = mv->mmu_segmentation_facets.get_facets(*mv, EnforcerBlockerType(extruder_idx)); if (!mv->is_model_part() || custom_facets.indices.empty()) continue; @@ -1425,7 +1426,7 @@ std::vector>> multi_material_segmentati visitor.reset(); visitor.line_to_test.a = line_start; visitor.line_to_test.b = line_end; - visitor.color = params.second; + visitor.color = extruder_idx; edge_grids[layer_idx].visit_cells_intersecting_line(line_start, line_end, visitor); append(painted_lines[layer_idx], std::move(painted_line_tmp)); diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index a1d8f65bfe..1c5c4f0216 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -1918,7 +1918,8 @@ void PrintObject::_slice(const std::vector &layer_height_profile) size_t region_count_before_change = this->num_regions(); std::vector>> segmented_regions = multi_material_segmentation_by_painting(*this); // Skip region with default extruder - for (size_t region_idx = 1; region_idx < 3; ++region_idx) { + const size_t num_extruders = this->print()->config().nozzle_diameter.size(); + for (size_t region_idx = 1; region_idx < num_extruders; ++region_idx) { std::vector c_layers(m_layers.size()); for (size_t layer_idx = 0; layer_idx < m_layers.size(); ++layer_idx) { for(const std::pair &colored_polygon : segmented_regions[layer_idx]) { diff --git a/src/libslic3r/TriangleSelector.cpp b/src/libslic3r/TriangleSelector.cpp index 7570075e56..ad69f6c7f9 100644 --- a/src/libslic3r/TriangleSelector.cpp +++ b/src/libslic3r/TriangleSelector.cpp @@ -550,8 +550,9 @@ indexed_triangle_set TriangleSelector::get_facets(EnforcerBlockerType state) con std::map> TriangleSelector::serialize() const { // Each original triangle of the mesh is assigned a number encoding its state - // or how it is split. Each triangle is encoded by 4 bits (xxyy): - // leaf triangle: xx = EnforcerBlockerType, yy = 0 + // or how it is split. Each triangle is encoded by 4 bits (xxyy) or 8 bits (zzzzxxyy): + // leaf triangle: xx = EnforcerBlockerType (Only values 0, 1, and 2. Value 3 is used as an indicator for additional 4 bits.), yy = 0 + // leaf triangle: xx = 0b11, yy = 0b00, zzzz = EnforcerBlockerType (subtracted by 3) // non-leaf: xx = special side, yy = number of split sides // These are bitwise appended and formed into one 64-bit integer. @@ -594,9 +595,17 @@ std::map> TriangleSelector::serialize() const serialize_recursive(tr.children[child_idx]); } else { // In case this is leaf, we better save information about its state. - assert(int(tr.get_state()) <= 3); - data.push_back(int(tr.get_state()) & 0b01); - data.push_back(int(tr.get_state()) & 0b10); + assert(int(tr.get_state()) <= 15); + if (3 <= int(tr.get_state()) && int(tr.get_state()) <= 15) { + data.insert(data.end(), {true, true}); + for (size_t bit_idx = 0; bit_idx < 4; ++bit_idx) { + size_t bit_mask = 0b0001 << bit_idx; + data.push_back(int(tr.get_state()) - 3 & bit_mask); + } + } else { + data.push_back(int(tr.get_state()) & 0b01); + data.push_back(int(tr.get_state()) & 0b10); + } ++stored_triangles; } }; @@ -614,7 +623,7 @@ void TriangleSelector::deserialize(const std::map> data) for (const auto& [triangle_id, code] : data) { assert(triangle_id < int(m_triangles.size())); assert(! code.empty()); - int processed_triangles = 0; + int processed_nibbles = 0; struct ProcessingInfo { int facet_id = 0; int processed_children = 0; @@ -626,18 +635,26 @@ void TriangleSelector::deserialize(const std::map> data) while (true) { // Read next triangle info. - int next_code = 0; - for (int i=3; i>=0; --i) { - next_code = next_code << 1; - next_code |= int(code[4 * processed_triangles + i]); - } - ++processed_triangles; + std::array next_code{}; + for(size_t nibble_idx = 0; nibble_idx < 2; ++nibble_idx) { + assert(nibble_idx < 2); + if(nibble_idx >= 1 && (next_code[0] >> 2) != 0b11) + break; - int num_of_split_sides = (next_code & 0b11); + for (int i = 3; i >= 0; --i) { + next_code[nibble_idx] = next_code[nibble_idx] << 1; + next_code[nibble_idx] |= int(code[4 * processed_nibbles + i]); + } + + ++processed_nibbles; + } + + int num_of_split_sides = (next_code[0] & 0b11); int num_of_children = num_of_split_sides != 0 ? num_of_split_sides + 1 : 0; bool is_split = num_of_children != 0; - EnforcerBlockerType state = EnforcerBlockerType(next_code >> 2); - int special_side = (next_code >> 2); + // Value of the second nibble was subtracted by 3, so it is added back. + EnforcerBlockerType state = EnforcerBlockerType(next_code[0] >> 2 == 0b11 ? next_code[1] + 3 : next_code[0] >> 2); + int special_side = (next_code[0] >> 2); // Take care of the first iteration separately, so handling of the others is simpler. if (parents.empty()) {