Browse Source

Merge perimeters of adjacent regions having the same perimeter settings

Alessandro Ranellucci 10 years ago
parent
commit
bcc8e356b2
2 changed files with 75 additions and 6 deletions
  1. 72 2
      lib/Slic3r/Layer.pm
  2. 3 4
      lib/Slic3r/Layer/Region.pm

+ 72 - 2
lib/Slic3r/Layer.pm

@@ -4,7 +4,7 @@ use warnings;
 
 use List::Util qw(first);
 use Slic3r::Geometry qw(scale chained_path);
-use Slic3r::Geometry::Clipper qw(union_ex);
+use Slic3r::Geometry::Clipper qw(union_ex intersection_ex);
 
 # the following two were previously generated by Moo
 sub print {
@@ -60,7 +60,77 @@ sub make_slices {
 sub make_perimeters {
     my $self = shift;
     Slic3r::debugf "Making perimeters for layer %d\n", $self->id;
-    $_->make_perimeters for @{$self->regions};
+    
+    # keep track of regions whose perimeters we have already generated
+    my %done = ();  # region_id => 1
+    
+    for my $region_id (0..$#{$self->regions}) {
+        next if $done{$region_id};
+        my $layerm = $self->regions->[$region_id];
+        $done{$region_id} = 1;
+        
+        # find compatible regions
+        my @layerms = ($layerm);
+        for my $i (($region_id+1)..$#{$self->regions}) {
+            my $config = $self->regions->[$i]->config;
+            my $layerm_config = $layerm->config;
+            
+            if ($config->perimeter_extruder == $layerm_config->perimeter_extruder
+                && $config->perimeters == $layerm_config->perimeters
+                && $config->perimeter_speed == $layerm_config->perimeter_speed
+                && $config->gap_fill_speed == $layerm_config->gap_fill_speed
+                && $config->overhangs == $layerm_config->overhangs
+                && $config->perimeter_extrusion_width == $layerm_config->perimeter_extrusion_width
+                && $config->thin_walls == $layerm_config->thin_walls
+                && $config->external_perimeters_first == $layerm_config->external_perimeters_first) {
+                push @layerms, $self->regions->[$i];
+                $done{$i} = 1;
+            }
+        }
+        
+        if (@layerms == 1) {  # optimization
+            $layerm->fill_surfaces->clear;
+            $layerm->make_perimeters($layerm->slices, $layerm->fill_surfaces);
+        } else {
+            # group slices (surfaces) according to number of extra perimeters
+            my %slices = ();  # extra_perimeters => [ surface, surface... ]
+            foreach my $surface (map @{$_->slices}, @layerms) {
+                my $extra = $surface->extra_perimeters;
+                $slices{$extra} ||= [];
+                push @{$slices{$extra}}, $surface;
+            }
+            
+            # merge the surfaces assigned to each group
+            my $new_slices = Slic3r::Surface::Collection->new;
+            foreach my $surfaces (values %slices) {
+                $new_slices->append(Slic3r::Surface->new(
+                    surface_type        => $surfaces->[0]->surface_type,
+                    extra_perimeters    => $surfaces->[0]->extra_perimeters,
+                    expolygon           => $_,
+                )) for @{union_ex([ map $_->p, @$surfaces ], 1)};
+            }
+            
+            # make perimeters
+            my $fill_surfaces = Slic3r::Surface::Collection->new;
+            $layerm->make_perimeters($new_slices, $fill_surfaces);
+            
+            # assign fill_surfaces to each layer
+            if ($fill_surfaces->count > 0) {
+                foreach my $lm (@layerms) {
+                    my $expolygons = intersection_ex(
+                        [ map $_->p, @$fill_surfaces ],
+                        [ map $_->p, @{$lm->slices} ],
+                    );
+                    $lm->fill_surfaces->clear;
+                    $lm->fill_surfaces->append(Slic3r::Surface->new(
+                        surface_type        => $fill_surfaces->[0]->surface_type,
+                        extra_perimeters    => $fill_surfaces->[0]->extra_perimeters,
+                        expolygon           => $_,
+                    )) for @$expolygons;
+                }
+            }
+        }
+    }
 }
 
 package Slic3r::Layer::Support;

+ 3 - 4
lib/Slic3r/Layer/Region.pm

@@ -41,7 +41,7 @@ sub flow {
 }
 
 sub make_perimeters {
-    my $self = shift;
+    my ($self, $slices, $fill_surfaces) = @_;
     
     # other perimeters
     my $perimeter_flow      = $self->flow(FLOW_ROLE_PERIMETER);
@@ -73,7 +73,6 @@ sub make_perimeters {
     my $ext_min_spacing     = $ext_pspacing * (1 - &Slic3r::INSET_OVERLAP_TOLERANCE);
     
     $self->perimeters->clear;
-    $self->fill_surfaces->clear;
     $self->thin_fills->clear;
     
     my @contours    = ();    # array of Polygons with ccw orientation
@@ -82,7 +81,7 @@ sub make_perimeters {
     
     # we need to process each island separately because we might have different
     # extra perimeters for each one
-    foreach my $surface (@{$self->slices}) {
+    foreach my $surface (@$slices) {
         # detect how many perimeters must be generated for this island
         my $loop_number = $self->config->perimeters + ($surface->extra_perimeters || 0);
         
@@ -187,7 +186,7 @@ sub make_perimeters {
         # and then we offset back and forth by half the infill spacing to only consider the
         # non-collapsing regions
         my $min_perimeter_infill_spacing = $ispacing * (1 - &Slic3r::INSET_OVERLAP_TOLERANCE);
-        $self->fill_surfaces->append(
+        $fill_surfaces->append(
             map Slic3r::Surface->new(expolygon => $_, surface_type => S_TYPE_INTERNAL),  # use a bogus surface type
             @{offset2_ex(
                 [ map @{$_->simplify_p(&Slic3r::SCALED_RESOLUTION)}, @{union_ex(\@last)} ],