diff --git a/lib/Slic3r/Layer/Region.pm b/lib/Slic3r/Layer/Region.pm index 6cbb58d20..8710bd880 100644 --- a/lib/Slic3r/Layer/Region.pm +++ b/lib/Slic3r/Layer/Region.pm @@ -447,6 +447,10 @@ sub _fill_gaps { sub prepare_fill_surfaces { my $self = shift; + # Note: in order to make the psPrepareInfill step idempotent, we should never + # alter fill_surfaces boundaries on which our idempotency relies since that's + # the only meaningful information returned by psPerimeters. + # if no solid layers are requested, turn top/bottom surfaces to internal if ($self->config->top_solid_layers == 0) { $_->surface_type(S_TYPE_INTERNAL) for @{$self->fill_surfaces->filter_by_type(S_TYPE_TOP)}; diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index 51b31a675..fab5d818a 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -80,7 +80,10 @@ sub apply_config { # All regions now have distinct settings. # Check whether applying the new region config defaults we'd get different regions. my $rearrange_regions = 0; + my @other_region_configs = (); REGION: foreach my $region_id (0..($self->region_count - 1)) { + my $region = $self->regions->[$region_id]; + my @this_region_configs = (); foreach my $object (@{$self->objects}) { foreach my $volume_id (@{ $object->get_region_volumes($region_id) }) { my $volume = $object->model_object->volumes->[$volume_id]; @@ -96,17 +99,40 @@ sub apply_config { $material_config->normalize; $new->apply_dynamic($material_config); } - if (!$new->equals($self->regions->[$region_id]->config)) { + if (defined first { !$_->equals($new) } @this_region_configs) { + # 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 $rearrange_regions = 1; last REGION; } + push @this_region_configs, $new; + + if (defined first { $_->equals($new) } @other_region_configs) { + # if the new config for this volume equals any of the other + # volume configs that are not currently associated to this + # region, it means the region subdivision does not make + # sense anymore + $rearrange_regions = 1; + last REGION; + } + + # if we're here and the new region config is different from the old + # one, we need to apply the new config and invalidate all objects + # (possible optimization: only invalidate objects using this region) + my $region_config_diff = $region->config->diff($new); + if (@$region_config_diff) { + $region->config->apply($new); + foreach my $o (@{$self->objects}) { + $o->invalidate_all_steps + if !$o->invalidate_state_by_config_options($region_config_diff); + } + } } } + push @other_region_configs, @this_region_configs; } - # Some optimization is possible: if the volumes-regions mappings don't change - # but still region configs are changed somehow, we could just apply the diff - # and invalidate the affected steps. if ($rearrange_regions) { # the current subdivision of regions does not make sense anymore. # we need to remove all objects and re-add them @@ -442,12 +468,14 @@ sub process { while (defined (my $obj_layer = $q->dequeue)) { my ($i, $region_id) = @$obj_layer; my $layerm = $object->layers->[$i]->regions->[$region_id]; + $layerm->fills->clear; $layerm->fills->append( $object->fill_maker->make_fill($layerm) ); } }, collect_cb => sub {}, no_threads_cb => sub { foreach my $layerm (map @{$_->regions}, @{$object->layers}) { + $layerm->fills->clear; $layerm->fills->append($object->fill_maker->make_fill($layerm)); } }, diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index 65456594f..1e0217c74 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -580,6 +580,10 @@ sub detect_surfaces_type { # clip surfaces to the fill boundaries foreach my $layer (@{$self->layers}) { my $layerm = $layer->regions->[$region_id]; + + # Note: this method should be idempotent, but fill_surfaces gets modified + # in place. However we're now only using its boundaries (which are invariant) + # so we're safe my $fill_boundaries = [ map $_->clone->p, @{$layerm->fill_surfaces} ]; $layerm->fill_surfaces->clear; foreach my $surface (@{$layerm->slices}) { diff --git a/xs/src/Print.cpp b/xs/src/Print.cpp index bd957a41a..950377db1 100644 --- a/xs/src/Print.cpp +++ b/xs/src/Print.cpp @@ -198,9 +198,14 @@ PrintObject::invalidate_state_by_config_options(const std::vector steps; - // this method only accepts PrintObjectConfig option keys + // this method only accepts PrintObjectConfig and PrintRegionConfig option keys for (std::vector::const_iterator opt_key = opt_keys.begin(); opt_key != opt_keys.end(); ++opt_key) { - if (*opt_key == "perimeters") { + if (*opt_key == "perimeters" + || *opt_key == "extra_perimeters" + || *opt_key == "gap_fill_speed" + || *opt_key == "overhangs" + || *opt_key == "perimeter_extrusion_width" + || *opt_key == "thin_walls") { steps.insert(posPerimeters); } else if (*opt_key == "resolution" || *opt_key == "layer_height" @@ -210,8 +215,10 @@ PrintObject::invalidate_state_by_config_options(const std::vector