Browse Source

When using raft, validate first layer height against support material extruder only instead of taking other extruders into account, thus potentially allowing larger nozzles to be used for it. #2701

Alessandro Ranellucci 10 years ago
parent
commit
095391d702
8 changed files with 85 additions and 29 deletions
  1. 5 4
      lib/Slic3r/Fill.pm
  2. 3 0
      lib/Slic3r/GUI/Tab.pm
  3. 16 4
      t/fill.t
  4. 6 6
      t/perimeters.t
  5. 3 0
      t/shells.t
  6. 12 2
      t/support.t
  7. 39 12
      xs/src/libslic3r/Print.cpp
  8. 1 1
      xs/src/libslic3r/PrintObject.cpp

+ 5 - 4
lib/Slic3r/Fill.pm

@@ -49,9 +49,10 @@ sub make_fill {
     
     Slic3r::debugf "Filling layer %d:\n", $layerm->id;
     
-    my $fill_density        = $layerm->config->fill_density;
-    my $infill_flow         = $layerm->flow(FLOW_ROLE_INFILL);
-    my $solid_infill_flow   = $layerm->flow(FLOW_ROLE_SOLID_INFILL);
+    my $fill_density            = $layerm->config->fill_density;
+    my $infill_flow             = $layerm->flow(FLOW_ROLE_INFILL);
+    my $solid_infill_flow       = $layerm->flow(FLOW_ROLE_SOLID_INFILL);
+    my $top_solid_infill_flow   = $layerm->flow(FLOW_ROLE_TOP_SOLID_INFILL);
     
     my @surfaces = ();
     
@@ -75,7 +76,7 @@ sub make_fill {
                 if ($groups[$i][0]->is_solid && (!$groups[$i][0]->is_bridge || $layerm->id == 0)) {
                     $is_solid[$i] = 1;
                     $fw[$i] = ($groups[$i][0]->surface_type == S_TYPE_TOP)
-                        ? $layerm->flow(FLOW_ROLE_TOP_SOLID_INFILL)->width
+                        ? $top_solid_infill_flow->width
                         : $solid_infill_flow->width;
                     $pattern[$i] = $groups[$i][0]->is_external
                         ? $layerm->config->external_fill_pattern

+ 3 - 0
lib/Slic3r/GUI/Tab.pm

@@ -745,11 +745,13 @@ sub _update {
             perimeter_speed small_perimeter_speed external_perimeter_speed);
     
     my $have_infill = $config->fill_density > 0;
+    # infill_extruder uses the same logic as in Print::extruders()
     $self->get_field($_)->toggle($have_infill)
         for qw(fill_pattern infill_every_layers infill_only_where_needed solid_infill_every_layers
             solid_infill_below_area infill_extruder);
     
     my $have_solid_infill = ($config->top_solid_layers > 0) || ($config->bottom_solid_layers > 0);
+    # solid_infill_extruder uses the same logic as in Print::extruders()
     $self->get_field($_)->toggle($have_solid_infill)
         for qw(external_fill_pattern infill_first solid_infill_extruder solid_infill_extrusion_width
             solid_infill_speed);
@@ -772,6 +774,7 @@ sub _update {
         for qw(skirt_distance skirt_height);
     
     my $have_brim = $config->brim_width > 0;
+    # perimeter_extruder uses the same logic as in Print::extruders()
     $self->get_field('perimeter_extruder')->toggle($have_perimeters || $have_brim);
     
     my $have_support_material = $config->support_material || $config->raft_layers > 0;

+ 16 - 4
t/fill.t

@@ -12,7 +12,7 @@ BEGIN {
 use List::Util qw(first sum);
 use Slic3r;
 use Slic3r::Geometry qw(X Y scale unscale convex_hull);
-use Slic3r::Geometry::Clipper qw(union diff_ex offset);
+use Slic3r::Geometry::Clipper qw(union diff diff_ex offset offset2_ex);
 use Slic3r::Surface qw(:types);
 use Slic3r::Test;
 
@@ -248,18 +248,27 @@ for my $pattern (qw(rectilinear honeycomb hilbertcurve concentric)) {
 {
     my $config = Slic3r::Config->new_from_defaults;
     $config->set('skirts', 0);
-    $config->set('perimeters', 0);
+    $config->set('perimeters', 1);
     $config->set('fill_density', 0);
     $config->set('top_solid_layers', 0);
     $config->set('bottom_solid_layers', 0);
     $config->set('solid_infill_below_area', 20000000);
     $config->set('solid_infill_every_layers', 2);
+    $config->set('perimeter_speed', 99);
+    $config->set('external_perimeter_speed', 99);
+    $config->set('cooling', 0);
+    $config->set('first_layer_speed', '100%');
     
     my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
     my %layers_with_extrusion = ();
     Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
         my ($self, $cmd, $args, $info) = @_;
-        $layers_with_extrusion{$self->Z} = 1 if $info->{extruding};
+        
+        if ($cmd eq 'G1' && $info->{dist_XY} > 0 && $info->{extruding}) {
+            if (($args->{F} // $self->F) != $config->perimeter_speed*60) {
+                $layers_with_extrusion{$self->Z} = ($args->{F} // $self->F);
+            }
+        }
     });
     
     ok !%layers_with_extrusion,
@@ -275,6 +284,7 @@ for my $pattern (qw(rectilinear honeycomb hilbertcurve concentric)) {
     $config->set('first_layer_height', 0.2);
     $config->set('nozzle_diameter', [0.35]);
     $config->set('infill_extruder', 2);
+    $config->set('solid_infill_extruder', 2);
     $config->set('infill_extrusion_width', 0.52);
     $config->set('solid_infill_extrusion_width', 0.52);
     $config->set('first_layer_extrusion_width', 0);
@@ -301,7 +311,9 @@ for my $pattern (qw(rectilinear honeycomb hilbertcurve concentric)) {
     my $grow_d = scale($config->infill_extrusion_width)/2;
     my $layer0_infill = union([ map @{$_->grow($grow_d)}, @{ $infill{0.2} } ]);
     my $layer1_infill = union([ map @{$_->grow($grow_d)}, @{ $infill{0.4} } ]);
-    my $diff = [ grep { $_->area > 2*(($grow_d*2)**2) } @{diff_ex($layer0_infill, $layer1_infill)} ];
+    my $diff = diff($layer0_infill, $layer1_infill);
+    $diff = offset2_ex($diff, -$grow_d, +$grow_d);
+    $diff = [ grep { $_->area > 2*(($grow_d*2)**2) } @$diff ];
     is scalar(@$diff), 0, 'no missing parts in solid shell when fill_density is 0';
 }
 

+ 6 - 6
t/perimeters.t

@@ -229,19 +229,19 @@ use Slic3r::Test;
     
     my $test = sub {
         my ($print) = @_;
-        my $has_bridges = 0;
+        my %z_with_bridges = ();  # z => 1
         Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
             my ($self, $cmd, $args, $info) = @_;
         
             if ($info->{extruding} && $info->{dist_XY} > 0) {
-                $has_bridges++ if ($args->{F} // $self->F) == $config->bridge_speed*60;
+                $z_with_bridges{$self->Z} = 1 if ($args->{F} // $self->F) == $config->bridge_speed*60;
             }
         });
-        return $has_bridges;
+        return scalar keys %z_with_bridges;
     };
-    ok !$test->(Slic3r::Test::init_print('V', config => $config)),
-        'no overhangs printed with bridge speed';
-    ok $test->(Slic3r::Test::init_print('V', config => $config, scale_xyz => [3,1,1])),
+    ok $test->(Slic3r::Test::init_print('V', config => $config)) == 1,
+        'no overhangs printed with bridge speed';  # except for the first internal solid layers above void
+    ok $test->(Slic3r::Test::init_print('V', config => $config, scale_xyz => [3,1,1])) > 1,
         'overhangs printed with bridge speed';
 }
 

+ 3 - 0
t/shells.t

@@ -72,6 +72,9 @@ use Slic3r::Test;
     $config->set('bottom_solid_layers', 0);
     ok $test->(), "no shells are applied when both top and bottom are set to zero";
     
+    $config->set('perimeters', 1);
+    $config->set('top_solid_layers', 3);
+    $config->set('bottom_solid_layers', 3);
     $config->set('fill_density', 0);
     ok $test->(), "proper number of shells is applied even when fill density is none";
 }

+ 12 - 2
t/support.t

@@ -1,4 +1,4 @@
-use Test::More tests => 24;
+use Test::More tests => 25;
 use strict;
 use warnings;
 
@@ -179,7 +179,7 @@ use Slic3r::Test;
     $test->(70);
 }
 
-TTT: {
+{
     my $config = Slic3r::Config->new_from_defaults;
     $config->set('brim_width',  0);
     $config->set('skirts', 0);
@@ -219,4 +219,14 @@ TTT: {
     ok !$test->(), 'bridge speed is not used when raft_layers > 0 and support_material_contact_distance == 0';
 }
 
+{
+    my $config = Slic3r::Config->new_from_defaults;
+    $config->set('raft_layers', 3);
+    $config->set('nozzle_diameter', [0.4, 1]);
+    $config->set('first_layer_height', 0.8);
+    $config->set('support_material_extruder', 2);
+    my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
+    ok Slic3r::Test::gcode($print), 'first_layer_height is validated with support material extruder nozzle diameter when using raft layers';
+}
+
 __END__

+ 39 - 12
xs/src/libslic3r/Print.cpp

@@ -305,9 +305,16 @@ Print::extruders() const
     std::set<size_t> extruders;
     
     FOREACH_REGION(this, region) {
-        extruders.insert((*region)->config.perimeter_extruder - 1);
-        extruders.insert((*region)->config.infill_extruder - 1);
-        extruders.insert((*region)->config.solid_infill_extruder - 1);
+        // these checks reflect the same logic used in the GUI for enabling/disabling
+        // extruder selection fields
+        if ((*region)->config.perimeters.value > 0 || this->config.brim_width.value > 0)
+            extruders.insert((*region)->config.perimeter_extruder - 1);
+        
+        if ((*region)->config.fill_density.value > 0)
+            extruders.insert((*region)->config.infill_extruder - 1);
+        
+        if ((*region)->config.top_solid_layers.value > 0 || (*region)->config.bottom_solid_layers.value > 0)
+            extruders.insert((*region)->config.solid_infill_extruder - 1);
     }
     FOREACH_OBJECT(this, object) {
         if ((*object)->has_support_material()) {
@@ -619,17 +626,37 @@ Print::validate() const
     }
     
     {
-        std::vector<double> layer_heights;
+        // find the smallest nozzle diameter
+        std::set<size_t> extruders = this->extruders();
+        if (extruders.empty())
+            throw PrintValidationException("The supplied settings will cause an empty print.");
+        
+        std::set<double> nozzle_diameters;
+        for (std::set<size_t>::iterator it = extruders.begin(); it != extruders.end(); ++it)
+            nozzle_diameters.insert(this->config.nozzle_diameter.get_at(*it));
+        double min_nozzle_diameter = *std::min_element(nozzle_diameters.begin(), nozzle_diameters.end());
+        
         FOREACH_OBJECT(this, i_object) {
             PrintObject* object = *i_object;
-            layer_heights.push_back(object->config.layer_height);
-            layer_heights.push_back(object->config.get_abs_value("first_layer_height"));
-        }
-        double max_layer_height = *std::max_element(layer_heights.begin(), layer_heights.end());
-        
-        std::set<size_t> extruders = this->extruders();
-        for (std::set<size_t>::iterator it = extruders.begin(); it != extruders.end(); ++it) {
-            if (max_layer_height > this->config.nozzle_diameter.get_at(*it))
+            
+            // validate first_layer_height
+            double first_layer_height = object->config.get_abs_value("first_layer_height");
+            double first_layer_min_nozzle_diameter;
+            if (object->config.raft_layers > 0) {
+                // if we have raft layers, only support material extruder is used on first layer
+                size_t first_layer_extruder = object->config.raft_layers == 1
+                    ? object->config.support_material_interface_extruder-1
+                    : object->config.support_material_extruder-1;
+                first_layer_min_nozzle_diameter = this->config.nozzle_diameter.get_at(first_layer_extruder);
+            } else {
+                // if we don't have raft layers, any nozzle diameter is potentially used in first layer
+                first_layer_min_nozzle_diameter = min_nozzle_diameter;
+            }
+            if (first_layer_height > first_layer_min_nozzle_diameter)
+                throw PrintValidationException("First layer height can't be greater than nozzle diameter");
+            
+            // validate layer_height
+            if (object->config.layer_height.value > min_nozzle_diameter)
                 throw PrintValidationException("Layer height can't be greater than nozzle diameter");
         }
     }

+ 1 - 1
xs/src/libslic3r/PrintObject.cpp

@@ -348,7 +348,7 @@ PrintObject::bridge_over_infill()
         size_t region_id = region - this->_print->regions.begin();
         
         double fill_density = (*region)->config.fill_density.value;
-        if (fill_density == 100 || fill_density == 0) continue;
+        if (fill_density == 100) continue;
         
         FOREACH_LAYER(this, layer_it) {
             if (layer_it == this->layers.begin()) continue;