From 0ca6b12da116bf59d0534d4f26637d8d1ed6636b Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Thu, 6 May 2021 13:00:57 +0200 Subject: [PATCH] Print/PrintObject/PrintRegion refactoring: Newly the PrintObjects own PrintRegions and Print contains references to PrintRegions owned by PrintObjects, so that a PrintRegion of the same content is referenced by Print only once. The refactoring is a WIP to support multi-material painting. --- src/libslic3r/GCode.cpp | 6 +- src/libslic3r/Print.cpp | 17 +-- src/libslic3r/Print.hpp | 24 ++-- src/libslic3r/PrintApply.cpp | 212 ++++++++++++++++------------------ src/libslic3r/PrintObject.cpp | 12 +- 5 files changed, 122 insertions(+), 149 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index ab68f00eb..01740ca7b 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -2110,7 +2110,9 @@ void GCode::process_layer( const LayerRegion *layerm = layer.regions()[region_id]; if (layerm == nullptr) continue; - const PrintRegion ®ion = layerm->region(); + // PrintObjects own the PrintRegions, thus the pointer to PrintRegion would be unique to a PrintObject, they would not + // identify the content of PrintRegion accross the whole print uniquely. Translate to a Print specific PrintRegion. + const PrintRegion ®ion = print.get_print_region(layerm->region().print_region_id()); // Now we must process perimeters and infills and create islands of extrusions in by_region std::map. // It is also necessary to save which extrusions are part of MM wiping and which are not. @@ -2169,7 +2171,7 @@ void GCode::process_layer( point_inside_surface(island_idx, extrusions->first_point())) { if (islands[island_idx].by_region.empty()) islands[island_idx].by_region.assign(print.num_print_regions(), ObjectByExtruder::Island::Region()); - islands[island_idx].by_region[region_id].append(entity_type, extrusions, entity_overrides); + islands[island_idx].by_region[region.print_region_id()].append(entity_type, extrusions, entity_overrides); break; } } diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index bd1b1f053..d0235c40e 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -31,6 +31,9 @@ namespace Slic3r { template class PrintState; template class PrintState; +PrintRegion::PrintRegion(const PrintRegionConfig &config) : PrintRegion(config, config.hash()) {} +PrintRegion::PrintRegion(PrintRegionConfig &&config) : PrintRegion(std::move(config), config.hash()) {} + void Print::clear() { tbb::mutex::scoped_lock lock(this->state_mutex()); @@ -39,24 +42,10 @@ void Print::clear() for (PrintObject *object : m_objects) delete object; m_objects.clear(); - for (PrintRegion *region : m_print_regions) - delete region; m_print_regions.clear(); m_model.clear_objects(); } -PrintRegion* Print::add_print_region() -{ - m_print_regions.emplace_back(new PrintRegion()); - return m_print_regions.back(); -} - -PrintRegion* Print::add_print_region(const PrintRegionConfig &config) -{ - m_print_regions.emplace_back(new PrintRegion(config)); - return m_print_regions.back(); -} - // Called by Print::apply(). // This method only accepts PrintConfig option keys. bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* new_config */, const std::vector &opt_keys) diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index f3d31896c..d341b7eec 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -61,14 +61,19 @@ enum PrintObjectStep { class PrintRegion { public: - PrintRegion() : m_refcnt(0) {} - PrintRegion(const PrintRegionConfig &config) : m_refcnt(0), m_config(config), m_config_hash(config.hash()) {} + PrintRegion() = default; + PrintRegion(const PrintRegionConfig &config); + PrintRegion(const PrintRegionConfig &config, const size_t config_hash) : m_config(config), m_config_hash(config_hash) {} + PrintRegion(PrintRegionConfig &&config); + PrintRegion(PrintRegionConfig &&config, const size_t config_hash) : m_config(std::move(config)), m_config_hash(config_hash) {} ~PrintRegion() = default; // Methods NOT modifying the PrintRegion's state: public: const PrintRegionConfig& config() const throw() { return m_config; } size_t config_hash() const throw() { return m_config_hash; } + // Identifier of this PrintRegion in the list of Print::m_print_regions. + int print_region_id() const throw() { return m_print_region_id; } // 1-based extruder identifier for this region and role. unsigned int extruder(FlowRole role) const; Flow flow(const PrintObject &object, FlowRole role, double layer_height, bool first_layer = false) const; @@ -87,14 +92,11 @@ public: void set_config(PrintRegionConfig &&config) { m_config = std::move(config); m_config_hash = m_config.hash(); } void config_apply_only(const ConfigBase &other, const t_config_option_keys &keys, bool ignore_nonexistent = false) { m_config.apply_only(other, keys, ignore_nonexistent); m_config_hash = m_config.hash(); } - -protected: - friend Print; - size_t m_refcnt; - private: + friend Print; PrintRegionConfig m_config; size_t m_config_hash; + int m_print_region_id = -1; }; inline bool operator==(const PrintRegion &lhs, const PrintRegion &rhs) { return lhs.config_hash() == rhs.config_hash() && lhs.config() == rhs.config(); } @@ -224,8 +226,8 @@ public: const SlicingParameters& slicing_parameters() const { return m_slicing_params; } static SlicingParameters slicing_parameters(const DynamicPrintConfig &full_config, const ModelObject &model_object, float object_max_z); - size_t num_printing_regions() const throw() { return m_region_volumes.size(); } - const PrintRegion& printing_region(size_t idx) const throw(); + size_t num_printing_regions() const throw() { return m_all_regions.size(); } + const PrintRegion& printing_region(size_t idx) const throw() { return *m_all_regions[idx]; } //FIXME returing all possible regions before slicing, thus some of the regions may not be slicing at the end. std::vector> all_regions() const; @@ -303,7 +305,7 @@ private: // This is the adjustment of the the Object's coordinate system towards PrintObject's coordinate system. Point m_center_offset; - std::set m_map_regions; + std::vector> m_all_regions; // vector of (layer height ranges and vectors of volume ids), indexed by region_id std::vector>> m_region_volumes; @@ -519,8 +521,6 @@ public: protected: // methods for handling regions PrintRegion& get_print_region(size_t idx) { return *m_print_regions[idx]; } - PrintRegion* add_print_region(); - PrintRegion* add_print_region(const PrintRegionConfig &config); // Invalidates the step, and its depending steps in Print. bool invalidate_step(PrintStep step); diff --git a/src/libslic3r/PrintApply.cpp b/src/libslic3r/PrintApply.cpp index 630d3a999..3679080e6 100644 --- a/src/libslic3r/PrintApply.cpp +++ b/src/libslic3r/PrintApply.cpp @@ -383,9 +383,6 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ delete object; } m_objects.clear(); - for (PrintRegion *region : m_print_regions) - delete region; - m_print_regions.clear(); m_model.assign_copy(model); for (const ModelObject *model_object : m_model.objects) model_object_status.emplace(model_object->id(), ModelObjectStatus::New); @@ -598,6 +595,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ } // 4) Generate PrintObjects from ModelObjects and their instances. + bool print_regions_reshuffled = false; { PrintObjectPtrs print_objects_new; print_objects_new.reserve(std::max(m_objects.size(), m_model.objects.size())); @@ -675,87 +673,72 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ update_apply_status(this->invalidate_steps({ psSkirt, psBrim, psWipeTower, psGCodeExport })); if (new_objects) update_apply_status(false); + print_regions_reshuffled = true; } print_object_status.clear(); } - // 5) Synchronize configs of ModelVolumes, synchronize AMF / 3MF materials (and their configs), refresh PrintRegions. - // Update reference counts of regions from the remaining PrintObjects and their volumes. - // Regions with zero references could and should be reused. - for (PrintRegion *region : m_print_regions) - region->m_refcnt = 0; - for (PrintObject *print_object : m_objects) { - int idx_region = 0; - for (const auto &volumes : print_object->m_region_volumes) { - if (! volumes.empty()) - ++ m_print_regions[idx_region]->m_refcnt; - ++ idx_region; - } - } - // All regions now have distinct settings. // Check whether applying the new region config defaults we'd get different regions. - for (size_t region_id = 0; region_id < m_print_regions.size(); ++ region_id) { - PrintRegion ®ion = *m_print_regions[region_id]; - PrintRegionConfig this_region_config; - bool this_region_config_set = false; - for (PrintObject *print_object : m_objects) { - const LayerRanges *layer_ranges; - { - auto it_status = model_object_status.find(ModelObjectStatus(print_object->model_object()->id())); - assert(it_status != model_object_status.end()); - assert(it_status->status != ModelObjectStatus::Deleted); - layer_ranges = &it_status->layer_ranges; - } - if (region_id < print_object->m_region_volumes.size()) { - for (const std::pair &volume_and_range : print_object->m_region_volumes[region_id]) { - const ModelVolume &volume = *print_object->model_object()->volumes[volume_and_range.second]; - const DynamicPrintConfig *layer_range_config = layer_ranges->config(volume_and_range.first); - if (this_region_config_set) { - // If the new config for this volume differs from the other - // volume configs currently associated to this region, it means - // the region subdivision does not make sense anymore. - if (! this_region_config.equals(PrintObject::region_config_from_model_volume(m_default_region_config, layer_range_config, volume, num_extruders))) - // Regions were split. Reset this print_object. - goto print_object_end; - } else { - this_region_config = PrintObject::region_config_from_model_volume(m_default_region_config, layer_range_config, volume, num_extruders); - for (size_t i = 0; i < region_id; ++ i) { - const PrintRegion ®ion_other = *m_print_regions[i]; - if (region_other.m_refcnt != 0 && region_other.config().equals(this_region_config)) - // Regions were merged. Reset this print_object. - goto print_object_end; - } - this_region_config_set = true; + for (PrintObject *print_object : m_objects) { + const LayerRanges *layer_ranges; + { + auto it_status = model_object_status.find(ModelObjectStatus(print_object->model_object()->id())); + assert(it_status != model_object_status.end()); + assert(it_status->status != ModelObjectStatus::Deleted); + layer_ranges = &it_status->layer_ranges; + } + bool some_object_region_modified = false; + bool regions_merged = false; + for (size_t region_id = 0; region_id < print_object->m_region_volumes.size(); ++ region_id) { + PrintRegion ®ion = *print_object->m_all_regions[region_id]; + PrintRegionConfig region_config; + bool region_config_set = false; + for (const std::pair &volume_and_range : print_object->m_region_volumes[region_id]) { + const ModelVolume &volume = *print_object->model_object()->volumes[volume_and_range.second]; + const DynamicPrintConfig *layer_range_config = layer_ranges->config(volume_and_range.first); + PrintRegionConfig this_region_config = PrintObject::region_config_from_model_volume(m_default_region_config, layer_range_config, volume, num_extruders); + if (region_config_set) { + if (this_region_config != region_config) { + regions_merged = true; + break; } + } else { + region_config = std::move(this_region_config); + region_config_set = true; } } - continue; - print_object_end: - update_apply_status(print_object->invalidate_all_steps()); - // Decrease the references to regions from this volume. - int ireg = 0; - for (const std::vector> &volumes : print_object->m_region_volumes) { - if (! volumes.empty()) - -- m_print_regions[ireg]->m_refcnt; - ++ ireg; - } - print_object->m_region_volumes.clear(); - } - if (this_region_config_set) { - t_config_option_keys diff = region.config().diff(this_region_config); - if (! diff.empty()) { + if (regions_merged) + break; + size_t region_config_hash = region_config.hash(); + bool modified = region.config_hash() != region_config_hash || region.config() != region_config; + some_object_region_modified |= modified; + if (some_object_region_modified) + // Verify whether this region was not merged with some other region. + for (size_t i = 0; i < region_id; ++ i) { + const PrintRegion ®ion_other = *print_object->m_all_regions[i]; + if (region_other.config_hash() == region_config_hash && region_other.config() == region_config) { + // Regions were merged. Reset this print_object. + regions_merged = true; + break; + } + } + if (modified) { // Stop the background process before assigning new configuration to the regions. - for (PrintObject *print_object : m_objects) - if (region_id < print_object->m_region_volumes.size() && ! print_object->m_region_volumes[region_id].empty()) - update_apply_status(print_object->invalidate_state_by_config_options(region.config(), this_region_config, diff)); - region.config_apply_only(this_region_config, diff, false); + t_config_option_keys diff = region.config().diff(region_config); + update_apply_status(print_object->invalidate_state_by_config_options(region.config(), region_config, diff)); + region.config_apply_only(region_config, diff, false); } } + if (regions_merged) { + // Two regions of a single object were either split or merged. This invalidates the whole slicing. + update_apply_status(print_object->invalidate_all_steps()); + print_object->m_region_volumes.clear(); + } } // Possibly add new regions for the newly added or resetted PrintObjects. - for (size_t idx_print_object = 0; idx_print_object < m_objects.size(); ++ idx_print_object) { + for (size_t idx_print_object = 0; idx_print_object < m_objects.size();) { PrintObject &print_object0 = *m_objects[idx_print_object]; const ModelObject &model_object = *print_object0.model_object(); const LayerRanges *layer_ranges; @@ -765,59 +748,64 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ assert(it_status->status != ModelObjectStatus::Deleted); layer_ranges = &it_status->layer_ranges; } - std::vector regions_in_object; - regions_in_object.reserve(64); - for (size_t i = idx_print_object; i < m_objects.size() && m_objects[i]->model_object() == &model_object; ++ i) { - PrintObject &print_object = *m_objects[i]; - bool fresh = print_object.m_region_volumes.empty(); + if (print_object0.m_region_volumes.empty()) { + // Fresh or completely invalidated print_object. Assign regions. unsigned int volume_id = 0; - unsigned int idx_region_in_object = 0; for (const ModelVolume *volume : model_object.volumes) { if (! volume->is_model_part() && ! volume->is_modifier()) { - ++ volume_id; - continue; - } + ++ volume_id; + continue; + } // Filter the layer ranges, so they do not overlap and they contain at least a single layer. // Now insert a volume with a layer range to its own region. for (auto it_range = layer_ranges->begin(); it_range != layer_ranges->end(); ++ it_range) { int region_id = -1; - if (&print_object == &print_object0) { - // Get the config applied to this volume. - PrintRegionConfig config = PrintObject::region_config_from_model_volume(m_default_region_config, it_range->second, *volume, num_extruders); - // Find an existing print region with the same config. - int idx_empty_slot = -1; - for (int i = 0; i < int(m_print_regions.size()); ++ i) { - if (m_print_regions[i]->m_refcnt == 0) { - if (idx_empty_slot == -1) - idx_empty_slot = i; - } else if (config.equals(m_print_regions[i]->config())) { - region_id = i; - break; - } - } - // If no region exists with the same config, create a new one. - if (region_id == -1) { - if (idx_empty_slot == -1) { - region_id = int(m_print_regions.size()); - this->add_print_region(config); - } else { - region_id = idx_empty_slot; - m_print_regions[region_id]->set_config(std::move(config)); - } + // Get the config applied to this volume. + PrintRegionConfig config = PrintObject::region_config_from_model_volume(m_default_region_config, it_range->second, *volume, num_extruders); + size_t hash = config.hash(); + for (size_t i = 0; i < print_object0.m_all_regions.size(); ++ i) + if (hash == print_object0.m_all_regions[i]->config_hash() && config == *print_object0.m_all_regions[i]) { + region_id = int(i); + break; } - regions_in_object.emplace_back(region_id); - } else - region_id = regions_in_object[idx_region_in_object ++]; - // Assign volume to a region. - if (fresh) { - if ((size_t)region_id >= print_object.m_region_volumes.size() || print_object.m_region_volumes[region_id].empty()) - ++ m_print_regions[region_id]->m_refcnt; - print_object.add_region_volume(region_id, volume_id, it_range->first); - } + // If no region exists with the same config, create a new one. + if (region_id == -1) { + region_id = int(print_object0.m_all_regions.size()); + print_object0.m_all_regions.emplace_back(std::make_unique(std::move(config), hash)); + } + print_object0.add_region_volume(region_id, volume_id, it_range->first); } - ++ volume_id; - } + ++ volume_id; + } + print_regions_reshuffled = true; } + for (++ idx_print_object; idx_print_object < m_objects.size() && m_objects[idx_print_object]->model_object() == &model_object; ++ idx_print_object) { + PrintObject &print_object = *m_objects[idx_print_object]; + if (print_object.m_region_volumes.empty()) { + // Copy region volumes and regions from print_object0. + print_object.m_region_volumes = print_object0.m_region_volumes; + print_object.m_all_regions.reserve(print_object0.m_all_regions.size()); + for (const std::unique_ptr ®ion : print_object0.m_all_regions) + print_object.m_all_regions.emplace_back(std::make_unique(*region)); + print_regions_reshuffled = true; + } + } + } + + if (print_regions_reshuffled) { + // Update Print::m_print_regions from objects. + struct cmp { bool operator() (const PrintRegion *l, const PrintRegion *r) const { return l->config_hash() == r->config_hash() && l->config() == r->config(); } }; + std::set region_set; + m_print_regions.clear(); + for (PrintObject *print_object : m_objects) + for (std::unique_ptr &print_region : print_object->m_all_regions) + if (auto it = region_set.find(print_region.get()); it == region_set.end()) { + int print_region_id = int(m_print_regions.size()); + m_print_regions.emplace_back(print_region.get()); + print_region->m_print_region_id = print_region_id; + } else { + print_region->m_print_region_id = (*it)->print_region_id(); + } } // Update SlicingParameters for each object where the SlicingParameters is not valid. diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index c96fe28cf..2986ea511 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -97,18 +97,12 @@ PrintBase::ApplyStatus PrintObject::set_instances(PrintInstances &&instances) return status; } -const PrintRegion& PrintObject::printing_region(size_t idx) const throw() -{ - return m_print->get_print_region(idx); -} - std::vector> PrintObject::all_regions() const { std::vector> out; - out.reserve(m_region_volumes.size()); - for (size_t i = 0; i < m_region_volumes.size(); ++ i) - if (! m_region_volumes[i].empty()) - out.emplace_back(m_print->get_print_region(i)); + out.reserve(m_all_regions.size()); + for (size_t i = 0; i < m_all_regions.size(); ++ i) + out.emplace_back(*m_all_regions[i]); return out; }