diff --git a/lib/Slic3r/Fill.pm b/lib/Slic3r/Fill.pm index e3acbe551..09fba7a29 100644 --- a/lib/Slic3r/Fill.pm +++ b/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 diff --git a/lib/Slic3r/GUI/Tab.pm b/lib/Slic3r/GUI/Tab.pm index d40763df4..00eb1d6fa 100644 --- a/lib/Slic3r/GUI/Tab.pm +++ b/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; diff --git a/t/fill.t b/t/fill.t index e43bdaadc..6fb05196e 100644 --- a/t/fill.t +++ b/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'; } diff --git a/t/perimeters.t b/t/perimeters.t index 11cc0cbd4..ed6f6b430 100644 --- a/t/perimeters.t +++ b/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'; } diff --git a/t/shells.t b/t/shells.t index a12858ae0..f3fd62d14 100644 --- a/t/shells.t +++ b/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"; } diff --git a/t/support.t b/t/support.t index 5ecf27b0c..2091b4432 100644 --- a/t/support.t +++ b/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__ diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index 2128095fa..d3bb43b3c 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -305,9 +305,16 @@ Print::extruders() const std::set 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 layer_heights; + // find the smallest nozzle diameter + std::set extruders = this->extruders(); + if (extruders.empty()) + throw PrintValidationException("The supplied settings will cause an empty print."); + + std::set nozzle_diameters; + for (std::set::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 extruders = this->extruders(); - for (std::set::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"); } } diff --git a/xs/src/libslic3r/PrintObject.cpp b/xs/src/libslic3r/PrintObject.cpp index 071247072..cf1ee20e4 100644 --- a/xs/src/libslic3r/PrintObject.cpp +++ b/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;