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.
This commit is contained in:
Vojtech Bubnik 2021-05-06 13:00:57 +02:00
parent 123c5af347
commit 0ca6b12da1
5 changed files with 122 additions and 149 deletions

View file

@ -2110,7 +2110,9 @@ void GCode::process_layer(
const LayerRegion *layerm = layer.regions()[region_id]; const LayerRegion *layerm = layer.regions()[region_id];
if (layerm == nullptr) if (layerm == nullptr)
continue; continue;
const PrintRegion &region = 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 &region = 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. // 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. // 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())) { point_inside_surface(island_idx, extrusions->first_point())) {
if (islands[island_idx].by_region.empty()) 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.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; break;
} }
} }

View file

@ -31,6 +31,9 @@ namespace Slic3r {
template class PrintState<PrintStep, psCount>; template class PrintState<PrintStep, psCount>;
template class PrintState<PrintObjectStep, posCount>; template class PrintState<PrintObjectStep, posCount>;
PrintRegion::PrintRegion(const PrintRegionConfig &config) : PrintRegion(config, config.hash()) {}
PrintRegion::PrintRegion(PrintRegionConfig &&config) : PrintRegion(std::move(config), config.hash()) {}
void Print::clear() void Print::clear()
{ {
tbb::mutex::scoped_lock lock(this->state_mutex()); tbb::mutex::scoped_lock lock(this->state_mutex());
@ -39,24 +42,10 @@ void Print::clear()
for (PrintObject *object : m_objects) for (PrintObject *object : m_objects)
delete object; delete object;
m_objects.clear(); m_objects.clear();
for (PrintRegion *region : m_print_regions)
delete region;
m_print_regions.clear(); m_print_regions.clear();
m_model.clear_objects(); 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(). // Called by Print::apply().
// This method only accepts PrintConfig option keys. // This method only accepts PrintConfig option keys.
bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* new_config */, const std::vector<t_config_option_key> &opt_keys) bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* new_config */, const std::vector<t_config_option_key> &opt_keys)

View file

@ -61,14 +61,19 @@ enum PrintObjectStep {
class PrintRegion class PrintRegion
{ {
public: public:
PrintRegion() : m_refcnt(0) {} PrintRegion() = default;
PrintRegion(const PrintRegionConfig &config) : m_refcnt(0), m_config(config), m_config_hash(config.hash()) {} 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; ~PrintRegion() = default;
// Methods NOT modifying the PrintRegion's state: // Methods NOT modifying the PrintRegion's state:
public: public:
const PrintRegionConfig& config() const throw() { return m_config; } const PrintRegionConfig& config() const throw() { return m_config; }
size_t config_hash() const throw() { return m_config_hash; } 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. // 1-based extruder identifier for this region and role.
unsigned int extruder(FlowRole role) const; unsigned int extruder(FlowRole role) const;
Flow flow(const PrintObject &object, FlowRole role, double layer_height, bool first_layer = false) 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 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) 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(); } { m_config.apply_only(other, keys, ignore_nonexistent); m_config_hash = m_config.hash(); }
protected:
friend Print;
size_t m_refcnt;
private: private:
friend Print;
PrintRegionConfig m_config; PrintRegionConfig m_config;
size_t m_config_hash; 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(); } 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; } 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); 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(); } size_t num_printing_regions() const throw() { return m_all_regions.size(); }
const PrintRegion& printing_region(size_t idx) const throw(); 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. //FIXME returing all possible regions before slicing, thus some of the regions may not be slicing at the end.
std::vector<std::reference_wrapper<const PrintRegion>> all_regions() const; std::vector<std::reference_wrapper<const PrintRegion>> all_regions() const;
@ -303,7 +305,7 @@ private:
// This is the adjustment of the the Object's coordinate system towards PrintObject's coordinate system. // This is the adjustment of the the Object's coordinate system towards PrintObject's coordinate system.
Point m_center_offset; Point m_center_offset;
std::set<PrintRegion> m_map_regions; std::vector<std::unique_ptr<PrintRegion>> m_all_regions;
// vector of (layer height ranges and vectors of volume ids), indexed by region_id // vector of (layer height ranges and vectors of volume ids), indexed by region_id
std::vector<std::vector<std::pair<t_layer_height_range, int>>> m_region_volumes; std::vector<std::vector<std::pair<t_layer_height_range, int>>> m_region_volumes;
@ -519,8 +521,6 @@ public:
protected: protected:
// methods for handling regions // methods for handling regions
PrintRegion& get_print_region(size_t idx) { return *m_print_regions[idx]; } 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. // Invalidates the step, and its depending steps in Print.
bool invalidate_step(PrintStep step); bool invalidate_step(PrintStep step);

View file

@ -383,9 +383,6 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
delete object; delete object;
} }
m_objects.clear(); m_objects.clear();
for (PrintRegion *region : m_print_regions)
delete region;
m_print_regions.clear();
m_model.assign_copy(model); m_model.assign_copy(model);
for (const ModelObject *model_object : m_model.objects) for (const ModelObject *model_object : m_model.objects)
model_object_status.emplace(model_object->id(), ModelObjectStatus::New); 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. // 4) Generate PrintObjects from ModelObjects and their instances.
bool print_regions_reshuffled = false;
{ {
PrintObjectPtrs print_objects_new; PrintObjectPtrs print_objects_new;
print_objects_new.reserve(std::max(m_objects.size(), m_model.objects.size())); print_objects_new.reserve(std::max(m_objects.size(), m_model.objects.size()));
@ -675,30 +673,13 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
update_apply_status(this->invalidate_steps({ psSkirt, psBrim, psWipeTower, psGCodeExport })); update_apply_status(this->invalidate_steps({ psSkirt, psBrim, psWipeTower, psGCodeExport }));
if (new_objects) if (new_objects)
update_apply_status(false); update_apply_status(false);
print_regions_reshuffled = true;
} }
print_object_status.clear(); 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. // All regions now have distinct settings.
// Check whether applying the new region config defaults we'd get different regions. // 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 &region = *m_print_regions[region_id];
PrintRegionConfig this_region_config;
bool this_region_config_set = false;
for (PrintObject *print_object : m_objects) { for (PrintObject *print_object : m_objects) {
const LayerRanges *layer_ranges; const LayerRanges *layer_ranges;
{ {
@ -707,55 +688,57 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
assert(it_status->status != ModelObjectStatus::Deleted); assert(it_status->status != ModelObjectStatus::Deleted);
layer_ranges = &it_status->layer_ranges; layer_ranges = &it_status->layer_ranges;
} }
if (region_id < print_object->m_region_volumes.size()) { 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 &region = *print_object->m_all_regions[region_id];
PrintRegionConfig region_config;
bool region_config_set = false;
for (const std::pair<t_layer_height_range, int> &volume_and_range : print_object->m_region_volumes[region_id]) { for (const std::pair<t_layer_height_range, int> &volume_and_range : print_object->m_region_volumes[region_id]) {
const ModelVolume &volume = *print_object->model_object()->volumes[volume_and_range.second]; const ModelVolume &volume = *print_object->model_object()->volumes[volume_and_range.second];
const DynamicPrintConfig *layer_range_config = layer_ranges->config(volume_and_range.first); const DynamicPrintConfig *layer_range_config = layer_ranges->config(volume_and_range.first);
if (this_region_config_set) { PrintRegionConfig this_region_config = PrintObject::region_config_from_model_volume(m_default_region_config, layer_range_config, volume, num_extruders);
// If the new config for this volume differs from the other if (region_config_set) {
// volume configs currently associated to this region, it means if (this_region_config != region_config) {
// the region subdivision does not make sense anymore. regions_merged = true;
if (! this_region_config.equals(PrintObject::region_config_from_model_volume(m_default_region_config, layer_range_config, volume, num_extruders))) break;
// Regions were split. Reset this print_object. }
goto print_object_end;
} else { } else {
this_region_config = PrintObject::region_config_from_model_volume(m_default_region_config, layer_range_config, volume, num_extruders); region_config = std::move(this_region_config);
region_config_set = true;
}
}
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) { for (size_t i = 0; i < region_id; ++ i) {
const PrintRegion &region_other = *m_print_regions[i]; const PrintRegion &region_other = *print_object->m_all_regions[i];
if (region_other.m_refcnt != 0 && region_other.config().equals(this_region_config)) if (region_other.config_hash() == region_config_hash && region_other.config() == region_config) {
// Regions were merged. Reset this print_object. // Regions were merged. Reset this print_object.
goto print_object_end; regions_merged = true;
} break;
this_region_config_set = true;
} }
} }
} if (modified) {
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<std::pair<t_layer_height_range, int>> &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()) {
// Stop the background process before assigning new configuration to the regions. // Stop the background process before assigning new configuration to the regions.
for (PrintObject *print_object : m_objects) t_config_option_keys diff = region.config().diff(region_config);
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(), region_config, diff));
update_apply_status(print_object->invalidate_state_by_config_options(region.config(), this_region_config, diff)); region.config_apply_only(region_config, diff, false);
region.config_apply_only(this_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. // 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]; PrintObject &print_object0 = *m_objects[idx_print_object];
const ModelObject &model_object = *print_object0.model_object(); const ModelObject &model_object = *print_object0.model_object();
const LayerRanges *layer_ranges; const LayerRanges *layer_ranges;
@ -765,13 +748,9 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
assert(it_status->status != ModelObjectStatus::Deleted); assert(it_status->status != ModelObjectStatus::Deleted);
layer_ranges = &it_status->layer_ranges; layer_ranges = &it_status->layer_ranges;
} }
std::vector<int> regions_in_object; if (print_object0.m_region_volumes.empty()) {
regions_in_object.reserve(64); // Fresh or completely invalidated print_object. Assign regions.
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();
unsigned int volume_id = 0; unsigned int volume_id = 0;
unsigned int idx_region_in_object = 0;
for (const ModelVolume *volume : model_object.volumes) { for (const ModelVolume *volume : model_object.volumes) {
if (! volume->is_model_part() && ! volume->is_modifier()) { if (! volume->is_model_part() && ! volume->is_modifier()) {
++ volume_id; ++ volume_id;
@ -781,42 +760,51 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
// Now insert a volume with a layer range to its own region. // 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) { for (auto it_range = layer_ranges->begin(); it_range != layer_ranges->end(); ++ it_range) {
int region_id = -1; int region_id = -1;
if (&print_object == &print_object0) {
// Get the config applied to this volume. // 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); 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. size_t hash = config.hash();
int idx_empty_slot = -1; for (size_t i = 0; i < print_object0.m_all_regions.size(); ++ i)
for (int i = 0; i < int(m_print_regions.size()); ++ i) { if (hash == print_object0.m_all_regions[i]->config_hash() && config == *print_object0.m_all_regions[i]) {
if (m_print_regions[i]->m_refcnt == 0) { region_id = int(i);
if (idx_empty_slot == -1)
idx_empty_slot = i;
} else if (config.equals(m_print_regions[i]->config())) {
region_id = i;
break; break;
} }
}
// If no region exists with the same config, create a new one. // If no region exists with the same config, create a new one.
if (region_id == -1) { if (region_id == -1) {
if (idx_empty_slot == -1) { region_id = int(print_object0.m_all_regions.size());
region_id = int(m_print_regions.size()); print_object0.m_all_regions.emplace_back(std::make_unique<PrintRegion>(std::move(config), hash));
this->add_print_region(config);
} else {
region_id = idx_empty_slot;
m_print_regions[region_id]->set_config(std::move(config));
}
}
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);
} }
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<Slic3r::PrintRegion> &region : print_object0.m_all_regions)
print_object.m_all_regions.emplace_back(std::make_unique<PrintRegion>(*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<const PrintRegion*, cmp> region_set;
m_print_regions.clear();
for (PrintObject *print_object : m_objects)
for (std::unique_ptr<Slic3r::PrintRegion> &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();
} }
} }

View file

@ -97,18 +97,12 @@ PrintBase::ApplyStatus PrintObject::set_instances(PrintInstances &&instances)
return status; return status;
} }
const PrintRegion& PrintObject::printing_region(size_t idx) const throw()
{
return m_print->get_print_region(idx);
}
std::vector<std::reference_wrapper<const PrintRegion>> PrintObject::all_regions() const std::vector<std::reference_wrapper<const PrintRegion>> PrintObject::all_regions() const
{ {
std::vector<std::reference_wrapper<const PrintRegion>> out; std::vector<std::reference_wrapper<const PrintRegion>> out;
out.reserve(m_region_volumes.size()); out.reserve(m_all_regions.size());
for (size_t i = 0; i < m_region_volumes.size(); ++ i) for (size_t i = 0; i < m_all_regions.size(); ++ i)
if (! m_region_volumes[i].empty()) out.emplace_back(*m_all_regions[i]);
out.emplace_back(m_print->get_print_region(i));
return out; return out;
} }