Bugfix: ambiguous semantics of the layers_count() method caused M73 to go beyond 100%. #1670

Conflicts:

	lib/Slic3r/GCode.pm
	lib/Slic3r/Print.pm
	lib/Slic3r/Print/Object.pm
This commit is contained in:
Alessandro Ranellucci 2014-01-11 17:40:09 +01:00
parent c0a74780cb
commit ea173cf815
4 changed files with 64 additions and 40 deletions

View File

@ -14,6 +14,7 @@ has 'standby_points' => (is => 'rw');
has 'enable_loop_clipping' => (is => 'rw', default => sub {1}); has 'enable_loop_clipping' => (is => 'rw', default => sub {1});
has 'enable_wipe' => (is => 'rw', default => sub {0}); # at least one extruder has wipe enabled has 'enable_wipe' => (is => 'rw', default => sub {0}); # at least one extruder has wipe enabled
has 'layer_count' => (is => 'ro', required => 1 ); has 'layer_count' => (is => 'ro', required => 1 );
has '_layer_index' => (is => 'rw', default => sub {-1}); # just a counter
has 'layer' => (is => 'rw'); has 'layer' => (is => 'rw');
has 'region' => (is => 'rw'); has 'region' => (is => 'rw');
has '_layer_islands' => (is => 'rw'); has '_layer_islands' => (is => 'rw');
@ -104,6 +105,7 @@ sub change_layer {
my ($self, $layer) = @_; my ($self, $layer) = @_;
$self->layer($layer); $self->layer($layer);
$self->_layer_index($self->_layer_index + 1);
# avoid computing islands and overhangs if they're not needed # avoid computing islands and overhangs if they're not needed
$self->_layer_islands($layer->islands); $self->_layer_islands($layer->islands);
@ -124,7 +126,7 @@ sub change_layer {
my $gcode = ""; my $gcode = "";
if ($self->print_config->gcode_flavor =~ /^(?:makerware|sailfish)$/) { if ($self->print_config->gcode_flavor =~ /^(?:makerware|sailfish)$/) {
$gcode .= sprintf "M73 P%s%s\n", $gcode .= sprintf "M73 P%s%s\n",
int(99 * ($layer->id / ($self->layer_count - 1))), int(99 * ($self->_layer_index / ($self->layer_count - 1))),
($self->print_config->gcode_comments ? ' ; update progress' : ''); ($self->print_config->gcode_comments ? ' ; update progress' : '');
} }
if ($self->print_config->first_layer_acceleration) { if ($self->print_config->first_layer_acceleration) {

View File

@ -315,9 +315,11 @@ sub init_extruders {
} }
} }
# this value is not supposed to be compared with $layer->id
# since they have different semantics
sub layer_count { sub layer_count {
my $self = shift; my $self = shift;
return max(map { scalar @{$_->layers} } @{$self->objects}); return max(map $_->layer_count, @{$self->objects});
} }
sub regions_count { sub regions_count {
@ -444,15 +446,15 @@ sub process {
items => sub { items => sub {
my @items = (); # [layer_id, region_id] my @items = (); # [layer_id, region_id]
for my $region_id (0 .. ($self->regions_count-1)) { for my $region_id (0 .. ($self->regions_count-1)) {
push @items, map [$_, $region_id], 0..($object->layer_count-1); push @items, map [$_, $region_id], 0..$#{$object->layers};
} }
@items; @items;
}, },
thread_cb => sub { thread_cb => sub {
my $q = shift; my $q = shift;
while (defined (my $obj_layer = $q->dequeue)) { while (defined (my $obj_layer = $q->dequeue)) {
my ($layer_id, $region_id) = @$obj_layer; my ($i, $region_id) = @$obj_layer;
my $layerm = $object->layers->[$layer_id]->regions->[$region_id]; my $layerm = $object->layers->[$i]->regions->[$region_id];
$layerm->fills->append( $object->fill_maker->make_fill($layerm) ); $layerm->fills->append( $object->fill_maker->make_fill($layerm) );
} }
}, },
@ -559,29 +561,31 @@ EOF
($type eq 'contour' ? 'white' : 'black'); ($type eq 'contour' ? 'white' : 'black');
}; };
my @layers = sort { $a->print_z <=> $b->print_z }
map { @{$_->layers}, @{$_->support_layers} }
@{$self->objects};
my $layer_id = -1;
my @previous_layer_slices = (); my @previous_layer_slices = ();
for my $layer_id (0..$self->layer_count-1) { for my $layer (@layers) {
my @layers = map $_->layers->[$layer_id], @{$self->objects}; $layer_id++;
printf $fh qq{ <g id="layer%d" slic3r:z="%s">\n}, $layer_id, +(grep defined $_, @layers)[0]->slice_z; # TODO: remove slic3r:z for raft layers
printf $fh qq{ <g id="layer%d" slic3r:z="%s">\n}, $layer_id, unscale($layer->slice_z);
my @current_layer_slices = (); my @current_layer_slices = ();
for my $obj_idx (0 .. $#{$self->objects}) { # sort slices so that the outermost ones come first
my $layer = $self->objects->[$obj_idx]->layers->[$layer_id] or next; my @slices = sort { $a->contour->encloses_point($b->contour->[0]) ? 0 : 1 } @{$layer->slices};
foreach my $copy (@{$layer->object->copies}) {
# sort slices so that the outermost ones come first foreach my $slice (@slices) {
my @slices = sort { $a->contour->contains_point($b->contour->first_point) ? 0 : 1 } @{$layer->slices}; my $expolygon = $slice->clone;
foreach my $copy (@{$self->objects->[$obj_idx]->_shifted_copies}) { $expolygon->translate(@$copy);
foreach my $slice (@slices) { $print_polygon->($expolygon->contour, 'contour');
my $expolygon = $slice->clone; $print_polygon->($_, 'hole') for @{$expolygon->holes};
$expolygon->translate(@$copy); push @current_layer_slices, $expolygon;
$print_polygon->($expolygon->contour, 'contour');
$print_polygon->($_, 'hole') for @{$expolygon->holes};
push @current_layer_slices, $expolygon;
}
} }
} }
# generate support material # generate support material
if ($self->has_support_material && $layer_id > 0) { if ($self->has_support_material && $layer->id > 0) {
my (@supported_slices, @unsupported_slices) = (); my (@supported_slices, @unsupported_slices) = ();
foreach my $expolygon (@current_layer_slices) { foreach my $expolygon (@current_layer_slices) {
my $intersection = intersection_ex( my $intersection = intersection_ex(

View File

@ -98,9 +98,12 @@ sub delete_all_copies {
$self->_trigger_copies; $self->_trigger_copies;
} }
# this is the *total* layer count
# this value is not supposed to be compared with $layer->id
# since they have different semantics
sub layer_count { sub layer_count {
my $self = shift; my $self = shift;
return scalar @{ $self->layers }; return scalar @{ $self->layers } + scalar @{ $self->support_layers };
} }
sub bounding_box { sub bounding_box {
@ -354,9 +357,9 @@ sub make_perimeters {
my $region_perimeters = $region->config->perimeters; my $region_perimeters = $region->config->perimeters;
if ($region->config->extra_perimeters && $region_perimeters > 0 && $region->config->fill_density > 0) { if ($region->config->extra_perimeters && $region_perimeters > 0 && $region->config->fill_density > 0) {
for my $layer_id (0 .. $self->layer_count-2) { for my $i (0 .. $#{$self->layers}-1) {
my $layerm = $self->layers->[$layer_id]->regions->[$region_id]; my $layerm = $self->layers->[$i]->regions->[$region_id];
my $upper_layerm = $self->layers->[$layer_id+1]->regions->[$region_id]; my $upper_layerm = $self->layers->[$i+1]->regions->[$region_id];
my $perimeter_spacing = $layerm->flow(FLOW_ROLE_PERIMETER)->scaled_spacing; my $perimeter_spacing = $layerm->flow(FLOW_ROLE_PERIMETER)->scaled_spacing;
my $overlap = $perimeter_spacing; # one perimeter my $overlap = $perimeter_spacing; # one perimeter
@ -393,8 +396,7 @@ sub make_perimeters {
# only add the perimeter if there's an intersection with the collapsed area # only add the perimeter if there's an intersection with the collapsed area
last CYCLE if !@{ intersection($diff, $hypothetical_perimeter) }; last CYCLE if !@{ intersection($diff, $hypothetical_perimeter) };
Slic3r::debugf " adding one more perimeter at layer %d\n", $layerm->id;
Slic3r::debugf " adding one more perimeter at layer %d\n", $layer_id;
$slice->extra_perimeters($extra_perimeters); $slice->extra_perimeters($extra_perimeters);
} }
} }
@ -404,11 +406,11 @@ sub make_perimeters {
Slic3r::parallelize( Slic3r::parallelize(
threads => $self->print->config->threads, threads => $self->print->config->threads,
items => sub { 0 .. ($self->layer_count-1) }, items => sub { 0 .. $#{$self->layers} },
thread_cb => sub { thread_cb => sub {
my $q = shift; my $q = shift;
while (defined (my $layer_id = $q->dequeue)) { while (defined (my $i = $q->dequeue)) {
$self->layers->[$layer_id]->make_perimeters; $self->layers->[$i]->make_perimeters;
} }
}, },
collect_cb => sub {}, collect_cb => sub {},
@ -428,7 +430,7 @@ sub detect_surfaces_type {
Slic3r::debugf "Detecting solid surfaces...\n"; Slic3r::debugf "Detecting solid surfaces...\n";
for my $region_id (0 .. ($self->print->regions_count-1)) { for my $region_id (0 .. ($self->print->regions_count-1)) {
for my $i (0 .. ($self->layer_count-1)) { for my $i (0 .. $#{$self->layers}) {
my $layerm = $self->layers->[$i]->regions->[$region_id]; my $layerm = $self->layers->[$i]->regions->[$region_id];
# prepare a reusable subroutine to make surface differences # prepare a reusable subroutine to make surface differences
@ -661,8 +663,8 @@ sub process_external_surfaces {
for my $region_id (0 .. ($self->print->regions_count-1)) { for my $region_id (0 .. ($self->print->regions_count-1)) {
$self->layers->[0]->regions->[$region_id]->process_external_surfaces(undef); $self->layers->[0]->regions->[$region_id]->process_external_surfaces(undef);
for my $layer_id (1 .. ($self->layer_count-1)) { for my $i (1 .. $#{$self->layers}) {
$self->layers->[$layer_id]->regions->[$region_id]->process_external_surfaces($self->layers->[$layer_id-1]); $self->layers->[$i]->regions->[$region_id]->process_external_surfaces($self->layers->[$i-1]);
} }
} }
} }
@ -673,7 +675,7 @@ sub discover_horizontal_shells {
Slic3r::debugf "==> DISCOVERING HORIZONTAL SHELLS\n"; Slic3r::debugf "==> DISCOVERING HORIZONTAL SHELLS\n";
for my $region_id (0 .. ($self->print->regions_count-1)) { for my $region_id (0 .. ($self->print->regions_count-1)) {
for (my $i = 0; $i < $self->layer_count; $i++) { for (my $i = 0; $i <= $#{$self->layers}; $i++) {
my $layerm = $self->layers->[$i]->regions->[$region_id]; my $layerm = $self->layers->[$i]->regions->[$region_id];
if ($layerm->config->solid_infill_every_layers && $layerm->config->fill_density > 0 if ($layerm->config->solid_infill_every_layers && $layerm->config->fill_density > 0
@ -705,7 +707,7 @@ sub discover_horizontal_shells {
abs($n - $i) <= $solid_layers-1; abs($n - $i) <= $solid_layers-1;
($type == S_TYPE_TOP) ? $n-- : $n++) { ($type == S_TYPE_TOP) ? $n-- : $n++) {
next if $n < 0 || $n >= $self->layer_count; next if $n < 0 || $n > $#{$self->layers};
Slic3r::debugf " looking for neighbors on layer %d...\n", $n; Slic3r::debugf " looking for neighbors on layer %d...\n", $n;
my $neighbor_fill_surfaces = $self->layers->[$n]->regions->[$region_id]->fill_surfaces; my $neighbor_fill_surfaces = $self->layers->[$n]->regions->[$region_id]->fill_surfaces;
@ -811,8 +813,7 @@ sub combine_infill {
return unless defined first { $_->config->infill_every_layers > 1 && $_->config->fill_density > 0 } @{$self->print->regions}; return unless defined first { $_->config->infill_every_layers > 1 && $_->config->fill_density > 0 } @{$self->print->regions};
my $layer_count = $self->layer_count; my @layer_heights = map $_->height, @{$self->layers};
my @layer_heights = map $self->layers->[$_]->height, 0 .. $layer_count-1;
for my $region_id (0 .. ($self->print->regions_count-1)) { for my $region_id (0 .. ($self->print->regions_count-1)) {
my $region = $self->print->regions->[$region_id]; my $region = $self->print->regions->[$region_id];
@ -922,7 +923,7 @@ sub combine_infill {
sub generate_support_material { sub generate_support_material {
my $self = shift; my $self = shift;
return unless ($self->config->support_material || $self->config->raft_layers > 0) return unless ($self->config->support_material || $self->config->raft_layers > 0)
&& $self->layer_count >= 2; && scalar(@{$self->layers}) >= 2;
my $first_layer_flow = Slic3r::Flow->new_from_width( my $first_layer_flow = Slic3r::Flow->new_from_width(
width => ($self->config->first_layer_extrusion_width || $self->config->support_material_extrusion_width), width => ($self->config->first_layer_extrusion_width || $self->config->support_material_extrusion_width),

View File

@ -1,4 +1,4 @@
use Test::More tests => 7; use Test::More tests => 8;
use strict; use strict;
use warnings; use warnings;
@ -81,4 +81,21 @@ use Slic3r::Test;
ok $print->total_used_filament > 0, 'final retraction is not considered in total used filament'; ok $print->total_used_filament > 0, 'final retraction is not considered in total used filament';
} }
{
my $config = Slic3r::Config->new_from_defaults;
$config->set('gcode_flavor', 'sailfish');
$config->set('raft_layers', 3);
my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
my @percent = ();
Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
my ($self, $cmd, $args, $info) = @_;
if ($cmd eq 'M73') {
push @percent, $args->{P};
}
});
# the extruder heater is turned off when M73 P100 is reached
ok !(defined first { $_ > 100 } @percent), 'M73 is never given more than 100%';
}
__END__ __END__