diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 22f3a4b132..d6b83c283b 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -2095,6 +2095,7 @@ void FacetsAnnotation::set_triangle_from_string(int triangle_id, const std::stri assert(m_data.triangles_to_split.empty() || m_data.triangles_to_split.back().triangle_idx < triangle_id); m_data.triangles_to_split.emplace_back(triangle_id, int(m_data.bitstream.size())); + const size_t bitstream_start_idx = m_data.bitstream.size(); for (auto it = str.crbegin(); it != str.crend(); ++it) { const char ch = *it; int dec = 0; @@ -2106,9 +2107,11 @@ void FacetsAnnotation::set_triangle_from_string(int triangle_id, const std::stri assert(false); // Convert to binary and append into code. - for (int i=0; i<4; ++i) + for (int i = 0; i < 4; ++i) m_data.bitstream.insert(m_data.bitstream.end(), bool(dec & (1 << i))); } + + m_data.update_used_states(bitstream_start_idx); } // Test whether the two models contain the same number of ModelObjects with the same set of IDs diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 67fb7ac517..214842d3e5 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -664,9 +664,9 @@ enum class ConversionType : int { class FacetsAnnotation final : public ObjectWithTimestamp { public: // Assign the content if the timestamp differs, don't assign an ObjectID. - void assign(const FacetsAnnotation& rhs) { if (! this->timestamp_matches(rhs)) { m_data = rhs.m_data; this->copy_timestamp(rhs); } } - void assign(FacetsAnnotation&& rhs) { if (! this->timestamp_matches(rhs)) { m_data = std::move(rhs.m_data); this->copy_timestamp(rhs); } } - const TriangleSelector::TriangleSplittingData &get_data() const throw() { return m_data; } + void assign(const FacetsAnnotation &rhs) { if (! this->timestamp_matches(rhs)) { m_data = rhs.m_data; this->copy_timestamp(rhs); } } + void assign(FacetsAnnotation &&rhs) { if (! this->timestamp_matches(rhs)) { m_data = std::move(rhs.m_data); this->copy_timestamp(rhs); } } + const TriangleSelector::TriangleSplittingData &get_data() const noexcept { return m_data; } bool set(const TriangleSelector& selector); indexed_triangle_set get_facets(const ModelVolume& mv, TriangleStateType type) const; indexed_triangle_set get_facets_strict(const ModelVolume& mv, TriangleStateType type) const; diff --git a/src/libslic3r/PrintApply.cpp b/src/libslic3r/PrintApply.cpp index 1ac2c72304..03e1dff23f 100644 --- a/src/libslic3r/PrintApply.cpp +++ b/src/libslic3r/PrintApply.cpp @@ -1375,9 +1375,20 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ if (const auto &volumes = print_object.model_object()->volumes; num_extruders > 1 && std::find_if(volumes.begin(), volumes.end(), [](const ModelVolume *v) { return ! v->mm_segmentation_facets.empty(); }) != volumes.end()) { - //FIXME be more specific! Don't enumerate extruders that are not used for painting! - painting_extruders.assign(num_extruders, 0); - std::iota(painting_extruders.begin(), painting_extruders.end(), 1); + + std::array(TriangleStateType::Count)> used_facet_states{}; + for (const ModelVolume *volume : volumes) { + const std::vector &volume_used_facet_states = volume->mm_segmentation_facets.get_data().used_states; + + assert(volume_used_facet_states.size() == used_facet_states.size()); + for (size_t state_idx = 0; state_idx < std::min(volume_used_facet_states.size(), used_facet_states.size()); ++state_idx) + used_facet_states[state_idx] |= volume_used_facet_states[state_idx]; + } + + for (size_t state_idx = static_cast(TriangleStateType::Extruder1); state_idx < used_facet_states.size(); ++state_idx) { + if (used_facet_states[state_idx]) + painting_extruders.emplace_back(state_idx); + } } 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. diff --git a/src/libslic3r/TriangleSelector.cpp b/src/libslic3r/TriangleSelector.cpp index 02070dfe70..c8c03fcfbe 100644 --- a/src/libslic3r/TriangleSelector.cpp +++ b/src/libslic3r/TriangleSelector.cpp @@ -1560,6 +1560,9 @@ TriangleSelector::TriangleSplittingData TriangleSelector::serialize() const { } else { // In case this is leaf, we better save information about its state. int n = int(tr.get_state()); + if (n < static_cast(TriangleStateType::Count)) + data.used_states[n] = true; + if (n >= 3) { assert(n <= 16); if (n <= 16) { @@ -1694,6 +1697,39 @@ void TriangleSelector::deserialize(const TriangleSplittingData &data, bool needs } } +void TriangleSelector::TriangleSplittingData::update_used_states(const size_t bitstream_start_idx) { + assert(bitstream_start_idx < this->bitstream.size()); + assert(!this->bitstream.empty() && this->bitstream.size() != bitstream_start_idx); + assert((this->bitstream.size() - bitstream_start_idx) % 4 == 0); + + if (this->bitstream.empty() || this->bitstream.size() == bitstream_start_idx) + return; + + size_t nibble_idx = bitstream_start_idx; + + auto read_next_nibble = [&data_bitstream = std::as_const(this->bitstream), &nibble_idx]() -> uint8_t { + assert(nibble_idx + 3 < data_bitstream.size()); + uint8_t code = 0; + for (size_t bit_idx = 0; bit_idx < 4; ++bit_idx) + code |= data_bitstream[nibble_idx++] << bit_idx; + return code; + }; + + while (nibble_idx < this->bitstream.size()) { + const uint8_t code = read_next_nibble(); + + if (const bool is_split = (code & 0b11) != 0; is_split) + continue; + + const uint8_t facet_state = (code & 0b1100) == 0b1100 ? read_next_nibble() + 3 : code >> 2; + assert(facet_state < this->used_states.size()); + if (facet_state >= this->used_states.size()) + continue; + + this->used_states[facet_state] = true; + } +} + // Lightweight variant of deserialization, which only tests whether a face of test_state exists. bool TriangleSelector::has_facets(const TriangleSplittingData &data, const TriangleStateType test_state) { // Depth-first queue of a number of unvisited children. diff --git a/src/libslic3r/TriangleSelector.hpp b/src/libslic3r/TriangleSelector.hpp index 75fe12383b..0e88fe3a7c 100644 --- a/src/libslic3r/TriangleSelector.hpp +++ b/src/libslic3r/TriangleSelector.hpp @@ -228,15 +228,31 @@ public: std::vector triangles_to_split; // Bit stream containing splitting information. std::vector bitstream; + // Array indicating which triangle state types are used (encoded inside bitstream). + std::vector used_states { std::vector(static_cast(TriangleStateType::Count), false) }; TriangleSplittingData() = default; - friend bool operator==(const TriangleSplittingData &lhs, const TriangleSplittingData &rhs) { return lhs.triangles_to_split == rhs.triangles_to_split && lhs.bitstream == rhs.bitstream; } + friend bool operator==(const TriangleSplittingData &lhs, const TriangleSplittingData &rhs) { + return lhs.triangles_to_split == rhs.triangles_to_split + && lhs.bitstream == rhs.bitstream + && lhs.used_states == rhs.used_states; + } + friend bool operator!=(const TriangleSplittingData &lhs, const TriangleSplittingData &rhs) { return !(lhs == rhs); } + // Reset all used states before they are recomputed based on the bitstream. + void reset_used_states() { + used_states.resize(static_cast(TriangleStateType::Count), false); + std::fill(used_states.begin(), used_states.end(), false); + } + + // Update used states based on the bitstream. It just iterated over the bitstream from the bitstream_start_idx till the end. + void update_used_states(size_t bitstream_start_idx); + private: friend class cereal::access; - template void serialize(Archive &ar) { ar(triangles_to_split, bitstream); } + template void serialize(Archive &ar) { ar(triangles_to_split, bitstream, used_states); } }; std::pair, std::vector> precompute_all_neighbors() const; @@ -302,6 +318,9 @@ public: // Load serialized data. Assumes that correct mesh is loaded. void deserialize(const TriangleSplittingData &data, bool needs_reset = true); + // Extract all used facet states from the given TriangleSplittingData. + static std::vector extract_used_facet_states(const TriangleSplittingData &data); + // For all triangles, remove the flag indicating that the triangle was selected by seed fill. void seed_fill_unselect_all_triangles();