Follow-up to a0ee41770d
see pull request #7323 for discussion what went wrong.
The original issue
Fix of Print::apply() creating hierarchy of regions for complex scenarios:
Unnecessary regions were created for a modifier over a volume or a modifier,
where the modifier did not modify any of its parent's properties.
This lead to an explosion of regions for this particular 3MF.
Fixes Non Responsive & Memory Leak when opening or changing this 3MF project #7220
After a0ee41770d
quite often regions were not re-regenerated. This shoul now be fixed
together with the original slowness & memory leak issue.
This commit is contained in:
parent
f30a018c5a
commit
a996f33579
1 changed files with 73 additions and 6 deletions
|
@ -604,12 +604,24 @@ void print_objects_regions_invalidate_keep_some_volumes(PrintObjectRegions &prin
|
|||
print_object_regions.cached_volume_ids.erase(print_object_regions.cached_volume_ids.begin() + last_cached_volume, print_object_regions.cached_volume_ids.end());
|
||||
}
|
||||
|
||||
// Find a bounding box of a volume's part intersecting layer_range. Such a bounding box will likely be smaller in XY than the full bounding box,
|
||||
// thus it will intersect with lower number of other volumes.
|
||||
const PrintObjectRegions::BoundingBox* find_volume_extents(const PrintObjectRegions::LayerRangeRegions &layer_range, const ModelVolume &volume)
|
||||
{
|
||||
auto it = lower_bound_by_predicate(layer_range.volumes.begin(), layer_range.volumes.end(), [&volume](const PrintObjectRegions::VolumeExtents &l){ return l.volume_id < volume.id(); });
|
||||
return it != layer_range.volumes.end() && it->volume_id == volume.id() ? &it->bbox : nullptr;
|
||||
}
|
||||
|
||||
// Find a bounding box of a topmost printable volume referenced by this modifier given this_region_id.
|
||||
const PrintObjectRegions::BoundingBox* find_modifier_volume_extents(const PrintObjectRegions::LayerRangeRegions &layer_range, const int this_region_id)
|
||||
{
|
||||
// Find the top-most printable volume of this modifier, or the printable volume itself.
|
||||
int parent_region_id = this_region_id;
|
||||
for (; ! layer_range.volume_regions[parent_region_id].model_volume->is_model_part(); parent_region_id = layer_range.volume_regions[parent_region_id].parent)
|
||||
assert(parent_region_id >= 0);
|
||||
return find_volume_extents(layer_range, *layer_range.volume_regions[parent_region_id].model_volume);
|
||||
}
|
||||
|
||||
PrintRegionConfig region_config_from_model_volume(const PrintRegionConfig &default_or_parent_region_config, const DynamicPrintConfig *layer_range_config, const ModelVolume &volume, size_t num_extruders);
|
||||
|
||||
void print_region_ref_inc(PrintRegion &r) { ++ r.m_ref_cnt; }
|
||||
|
@ -634,11 +646,54 @@ bool verify_update_print_object_regions(
|
|||
print_region_ref_reset(*region);
|
||||
|
||||
// Verify and / or update PrintRegions produced by ModelVolumes, layer range modifiers, modifier volumes.
|
||||
for (PrintObjectRegions::LayerRangeRegions &layer_range : print_object_regions.layer_ranges)
|
||||
for (PrintObjectRegions::LayerRangeRegions &layer_range : print_object_regions.layer_ranges) {
|
||||
// Each modifier ModelVolume intersecting this layer_range shall be referenced here at least once if it intersects some
|
||||
// printable ModelVolume at this layer_range even if it does not modify its overlapping printable ModelVolume configuration yet.
|
||||
// VolumeRegions reference ModelVolumes in layer_range.volume_regions the order they are stored in ModelObject volumes.
|
||||
// Remember whether a given modifier ModelVolume was visited already.
|
||||
auto it_model_volume_modifier_last = model_volumes.end();
|
||||
for (PrintObjectRegions::VolumeRegion ®ion : layer_range.volume_regions)
|
||||
if (region.model_volume->is_model_part() || region.model_volume->is_modifier()) {
|
||||
auto it_model_volume = lower_bound_by_predicate(model_volumes.begin(), model_volumes.end(), [®ion](const ModelVolume *l){ return l->id() < region.model_volume->id(); });
|
||||
assert(it_model_volume != model_volumes.end() && (*it_model_volume)->id() == region.model_volume->id());
|
||||
if (region.model_volume->is_modifier() && it_model_volume != it_model_volume_modifier_last) {
|
||||
// A modifier ModelVolume is visited for the first time.
|
||||
// A visited modifier may not have had parent volume_regions created overlapping with some model parts or modifiers,
|
||||
// if the visited modifier did not modify their properties. Now the visited modifier's configuration may have changed,
|
||||
// which may require new regions to be created.
|
||||
it_model_volume_modifier_last = it_model_volume;
|
||||
int this_region_id = int(®ion - layer_range.volume_regions.data());
|
||||
int next_region_id = this_region_id + 1;
|
||||
const PrintObjectRegions::BoundingBox *bbox = find_volume_extents(layer_range, *region.model_volume);
|
||||
assert(bbox);
|
||||
for (int parent_region_id = this_region_id - 1; parent_region_id >= 0; -- parent_region_id) {
|
||||
const PrintObjectRegions::VolumeRegion &parent_region = layer_range.volume_regions[parent_region_id];
|
||||
assert(parent_region.model_volume != region.model_volume);
|
||||
if (parent_region.model_volume->is_model_part() || parent_region.model_volume->is_modifier()) {
|
||||
// volume_regions are produced in decreasing order of parent volume_regions ids.
|
||||
// Some regions may not have been generated the last time by generate_print_object_regions().
|
||||
assert(next_region_id == int(layer_range.volume_regions.size()) ||
|
||||
layer_range.volume_regions[next_region_id].model_volume != region.model_volume ||
|
||||
layer_range.volume_regions[next_region_id].parent <= parent_region_id);
|
||||
if (next_region_id < int(layer_range.volume_regions.size()) &&
|
||||
layer_range.volume_regions[next_region_id].model_volume == region.model_volume &&
|
||||
layer_range.volume_regions[next_region_id].parent == parent_region_id) {
|
||||
// A parent region is already overridden.
|
||||
++ next_region_id;
|
||||
} else {
|
||||
// Such parent region does not exist. If it is needed, then we need to reslice.
|
||||
const PrintObjectRegions::BoundingBox *parent_bbox = find_modifier_volume_extents(layer_range, parent_region_id);
|
||||
assert(parent_bbox != nullptr);
|
||||
if (parent_bbox->intersects(*bbox))
|
||||
// Only create new region for a modifier, which actually modifies config of it's parent.
|
||||
if (PrintRegionConfig config = region_config_from_model_volume(parent_region.region->config(), nullptr, **it_model_volume, num_extruders);
|
||||
config != parent_region.region->config())
|
||||
// This modifier newly overrides a region, which it did not before. We need to reslice.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
PrintRegionConfig cfg = region.parent == -1 ?
|
||||
region_config_from_model_volume(default_region_config, layer_range.config, **it_model_volume, num_extruders) :
|
||||
region_config_from_model_volume(layer_range.volume_regions[region.parent].region->config(), nullptr, **it_model_volume, num_extruders);
|
||||
|
@ -657,6 +712,7 @@ bool verify_update_print_object_regions(
|
|||
}
|
||||
print_region_ref_inc(*region.region);
|
||||
}
|
||||
}
|
||||
|
||||
// Verify and / or update PrintRegions produced by color painting.
|
||||
for (const PrintObjectRegions::LayerRangeRegions &layer_range : print_object_regions.layer_ranges)
|
||||
|
@ -851,17 +907,28 @@ static PrintObjectRegions* generate_print_object_regions(
|
|||
} else {
|
||||
assert(volume.is_modifier());
|
||||
// Modifiers may be chained one over the other. Check for overlap, merge DynamicPrintConfigs.
|
||||
for (int parent_region_id = int(layer_range.volume_regions.size()) - 1; parent_region_id >= 0; -- parent_region_id)
|
||||
if (const PrintObjectRegions::VolumeRegion &parent_region = layer_range.volume_regions[parent_region_id];
|
||||
parent_region.model_volume->is_model_part() || parent_region.model_volume->is_modifier()) {
|
||||
const PrintObjectRegions::BoundingBox *parent_bbox = find_volume_extents(layer_range, *parent_region.model_volume);
|
||||
bool added = false;
|
||||
int parent_model_part_id = -1;
|
||||
for (int parent_region_id = int(layer_range.volume_regions.size()) - 1; parent_region_id >= 0; -- parent_region_id) {
|
||||
const PrintObjectRegions::VolumeRegion &parent_region = layer_range.volume_regions[parent_region_id];
|
||||
const ModelVolume &parent_volume = *parent_region.model_volume;
|
||||
if (parent_volume.is_model_part() || parent_volume.is_modifier()) {
|
||||
const PrintObjectRegions::BoundingBox *parent_bbox = find_modifier_volume_extents(layer_range, parent_region_id);
|
||||
assert(parent_bbox != nullptr);
|
||||
if (parent_bbox->intersects(*bbox))
|
||||
// Only create new region for a modifier, which actually modifies config of it's parent.
|
||||
if (PrintRegionConfig config = region_config_from_model_volume(parent_region.region->config(), nullptr, volume, num_extruders);
|
||||
config != parent_region.region->config())
|
||||
config != parent_region.region->config()) {
|
||||
added = true;
|
||||
layer_range.volume_regions.push_back({ &volume, parent_region_id, get_create_region(std::move(config)), bbox });
|
||||
} else if (parent_model_part_id == -1 && parent_volume.is_model_part())
|
||||
parent_model_part_id = parent_region_id;
|
||||
}
|
||||
}
|
||||
if (! added && parent_model_part_id >= 0)
|
||||
// This modifier does not override any printable volume's configuration, however it may in the future.
|
||||
// Store it so that verify_update_print_object_regions() will handle this modifier correctly if its configuration changes.
|
||||
layer_range.volume_regions.push_back({ &volume, parent_model_part_id, layer_range.volume_regions[parent_model_part_id].region, bbox });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue