From f6569cf3596cf850d221175ce68006750433c1b6 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Thu, 8 Aug 2013 14:41:23 +0200 Subject: [PATCH 01/25] Minor error causing support material to fail when first_layer_height was expressed in % (caught by regression test). #1371 --- lib/Slic3r/Print/Object.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index 2ca0e0d176..6ad1777158 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -910,7 +910,7 @@ sub generate_support_material { ###$contact_z = $layer->print_z - $layer->height; # ignore this contact area if it's too low - next if $contact_z < $Slic3r::Config->first_layer_height; + next if $contact_z < $Slic3r::Config->get_value('first_layer_height'); $contact{$contact_z} = [ @contact ]; $overhang{$contact_z} = [ @overhang ]; From 3427b29a935c24aeda4a9e0c08e1358842995ffa Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Thu, 8 Aug 2013 16:27:41 +0200 Subject: [PATCH 02/25] Fix wrong slices when many overlapping facets were present in the model --- lib/Slic3r/Layer/Region.pm | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/Slic3r/Layer/Region.pm b/lib/Slic3r/Layer/Region.pm index 93574e26d8..df45b1ffec 100644 --- a/lib/Slic3r/Layer/Region.pm +++ b/lib/Slic3r/Layer/Region.pm @@ -5,7 +5,8 @@ use List::Util qw(sum first); use Slic3r::ExtrusionPath ':roles'; use Slic3r::Geometry qw(PI A B scale chained_path_items points_coincide); use Slic3r::Geometry::Clipper qw(safety_offset union_ex diff_ex intersection_ex - offset offset2 offset2_ex PFT_EVENODD union_pt traverse_pt diff intersection); + offset offset2 offset2_ex PFT_EVENODD union_pt traverse_pt diff intersection + union diff); use Slic3r::Surface ':types'; has 'layer' => ( @@ -131,23 +132,22 @@ sub _merge_loops { # winding order. # TODO: find a faster algorithm for this. my @loops = sort { $a->encloses_point($b->[0]) ? 0 : 1 } @$loops; # outer first - $safety_offset //= scale 0.0499; - @loops = @{ safety_offset(\@loops, $safety_offset) }; - my $expolygons = []; - while (my $loop = shift @loops) { - bless $loop, 'Slic3r::Polygon'; - if ($loop->is_counter_clockwise) { - $expolygons = union_ex([ $loop, map @$_, @$expolygons ]); - } else { - $expolygons = diff_ex([ map @$_, @$expolygons ], [$loop]); - } + # we don't perform a safety offset now because it might reverse cw loops + my $slices = []; + foreach my $loop (@loops) { + $slices = $loop->is_counter_clockwise + ? union([ $loop, @$slices ]) + : diff($slices, [$loop]); } - $expolygons = [ map $_->offset_ex(-$safety_offset), @$expolygons ]; + + # perform a safety offset to merge very close facets (TODO: find test case for this) + $safety_offset //= scale 0.0499; + $slices = [ offset2_ex($slices, +$safety_offset, -$safety_offset) ]; Slic3r::debugf " %d surface(s) having %d holes detected from %d polylines\n", - scalar(@$expolygons), scalar(map $_->holes, @$expolygons), scalar(@$loops); + scalar(@$slices), scalar(map $_->holes, @$slices), scalar(@$loops) if $Slic3r::debug; - return map Slic3r::Surface->new(expolygon => $_, surface_type => S_TYPE_INTERNAL), @$expolygons; + return map Slic3r::Surface->new(expolygon => $_, surface_type => S_TYPE_INTERNAL), @$slices; } sub make_perimeters { From cde662cb51677e782db9dee2fe227f58ee9ed950 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Fri, 9 Aug 2013 14:22:41 +0200 Subject: [PATCH 03/25] Fix collision detection for brim --- lib/Slic3r/Print.pm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index 5bcc4b92a3..1ca8ef38eb 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -680,8 +680,9 @@ sub make_brim { for my $i (reverse 1 .. $num_loops) { # JT_SQUARE ensures no vertex is outside the given offset distance # -0.5 because islands are not represented by their centerlines - # TODO: we need the offset inwards/offset outwards logic to avoid overlapping extrusions - push @loops, offset2(\@islands, ($i - 1.5) * $flow->scaled_spacing, +1.0 * $flow->scaled_spacing, undef, JT_SQUARE); + # (first offset more, then step back - reverse order than the one used for + # perimeters because here we're offsetting outwards) + push @loops, offset2(\@islands, ($i + 1.0) * $flow->scaled_spacing, -1.5 * $flow->scaled_spacing, undef, JT_SQUARE); } @{$self->brim} = map Slic3r::ExtrusionLoop->pack( From 99816e07a6621912af9fe945f8d14e2e83c6339c Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Fri, 9 Aug 2013 14:30:43 +0200 Subject: [PATCH 04/25] New --first-layer-acceleration option --- README.markdown | 3 +++ lib/Slic3r/Config.pm | 8 ++++++++ lib/Slic3r/GCode.pm | 23 ++++++++++++++++------- lib/Slic3r/GUI/Tab.pm | 2 +- slic3r.pl | 3 +++ 5 files changed, 31 insertions(+), 8 deletions(-) diff --git a/README.markdown b/README.markdown index ad304dc1b9..ca8e7a3466 100644 --- a/README.markdown +++ b/README.markdown @@ -172,6 +172,9 @@ The author of the Silk icon set is Mark James. --bridge-acceleration Overrides firmware's default acceleration for bridges. (mm/s^2, set zero to disable; default: 0) + --first-layer-acceleration + Overrides firmware's default acceleration for first layer. (mm/s^2, set zero + to disable; default: 0) --default-acceleration Acceleration will be reset to this value after the specific settings above have been applied. (mm/s^2, set zero to disable; default: 130) diff --git a/lib/Slic3r/Config.pm b/lib/Slic3r/Config.pm index 0d89b79ee2..ddf3fe6e37 100644 --- a/lib/Slic3r/Config.pm +++ b/lib/Slic3r/Config.pm @@ -369,6 +369,14 @@ our $Options = { type => 'f', default => 0, }, + 'first_layer_acceleration' => { + label => 'First layer', + tooltip => 'This is the acceleration your printer will use for first layer. Set zero to disable acceleration control for first layer.', + sidetext => 'mm/s²', + cli => 'first-layer-acceleration=f', + type => 'f', + default => 0, + }, # accuracy options 'layer_height' => { diff --git a/lib/Slic3r/GCode.pm b/lib/Slic3r/GCode.pm index 08c5c89be5..752ead5c19 100644 --- a/lib/Slic3r/GCode.pm +++ b/lib/Slic3r/GCode.pm @@ -116,6 +116,13 @@ sub change_layer { int(99 * ($layer->id / ($self->layer_count - 1))), ($self->config->gcode_comments ? ' ; update progress' : ''); } + if ($self->config->first_layer_acceleration) { + if ($layer->id == 0) { + $gcode .= $self->set_acceleration($self->config->first_layer_acceleration); + } elsif ($layer->id == 1) { + $gcode .= $self->set_acceleration($self->config->default_acceleration); + } + } return $gcode; } @@ -289,14 +296,16 @@ sub extrude_path { # adjust acceleration my $acceleration; - if ($self->config->perimeter_acceleration && $path->is_perimeter) { - $acceleration = $self->config->perimeter_acceleration; - } elsif ($self->config->infill_acceleration && $path->is_fill) { - $acceleration = $self->config->infill_acceleration; - } elsif ($self->config->infill_acceleration && $path->is_bridge) { - $acceleration = $self->config->bridge_acceleration; + if (!$self->config->first_layer_acceleration || $self->layer->id != 0) { + if ($self->config->perimeter_acceleration && $path->is_perimeter) { + $acceleration = $self->config->perimeter_acceleration; + } elsif ($self->config->infill_acceleration && $path->is_fill) { + $acceleration = $self->config->infill_acceleration; + } elsif ($self->config->infill_acceleration && $path->is_bridge) { + $acceleration = $self->config->bridge_acceleration; + } + $gcode .= $self->set_acceleration($acceleration) if $acceleration; } - $gcode .= $self->set_acceleration($acceleration) if $acceleration; my $area; # mm^3 of extrudate per mm of tool movement if ($path->is_bridge) { diff --git a/lib/Slic3r/GUI/Tab.pm b/lib/Slic3r/GUI/Tab.pm index 70fd3962a8..bdf5d82695 100644 --- a/lib/Slic3r/GUI/Tab.pm +++ b/lib/Slic3r/GUI/Tab.pm @@ -461,7 +461,7 @@ sub build { }, { title => 'Acceleration control (advanced)', - options => [qw(perimeter_acceleration infill_acceleration bridge_acceleration default_acceleration)], + options => [qw(perimeter_acceleration infill_acceleration bridge_acceleration first_layer_acceleration default_acceleration)], }, ]); diff --git a/slic3r.pl b/slic3r.pl index b96b112ed1..8818c91514 100755 --- a/slic3r.pl +++ b/slic3r.pl @@ -255,6 +255,9 @@ $j --bridge-acceleration Overrides firmware's default acceleration for bridges. (mm/s^2, set zero to disable; default: $config->{bridge_acceleration}) + --first-layer-acceleration + Overrides firmware's default acceleration for first layer. (mm/s^2, set zero + to disable; default: $config->{first_layer_acceleration}) --default-acceleration Acceleration will be reset to this value after the specific settings above have been applied. (mm/s^2, set zero to disable; default: $config->{travel_speed}) From 67f5b7ab14b0898ed2cd04c1070d806602ac3699 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Fri, 9 Aug 2013 14:33:20 +0200 Subject: [PATCH 05/25] Require --default-acceleration when other acceleration settings are used --- lib/Slic3r/Config.pm | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/Slic3r/Config.pm b/lib/Slic3r/Config.pm index ddf3fe6e37..a48f2f0f41 100644 --- a/lib/Slic3r/Config.pm +++ b/lib/Slic3r/Config.pm @@ -1385,6 +1385,11 @@ sub validate { die "Invalid value for --extrusion-multiplier\n" if defined first { $_ <= 0 } @{$self->extrusion_multiplier}; + # --default-acceleration + die "Invalid zero value for --default-acceleration when using other acceleration settings\n" + if ($self->perimeter_acceleration || $self->infill_acceleration || $self->bridge_acceleration || $self->first_layer_acceleration) + && !$self->default_acceleration; + # general validation, quick and dirty foreach my $opt_key (keys %$Options) { my $opt = $Options->{$opt_key}; From 5d80c26b2978ab0e7843f21ead0cb7f58162f30e Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Fri, 9 Aug 2013 14:55:36 +0200 Subject: [PATCH 06/25] Adjust collision detection for brim and include support islands inside the only_retract_when_crossing_perimeters logic --- lib/Slic3r/GCode.pm | 17 +++++++++++++---- lib/Slic3r/Layer.pm | 25 ++++++++++++++----------- lib/Slic3r/Print.pm | 2 +- lib/Slic3r/Print/Object.pm | 1 + 4 files changed, 29 insertions(+), 16 deletions(-) diff --git a/lib/Slic3r/GCode.pm b/lib/Slic3r/GCode.pm index 752ead5c19..53e8715519 100644 --- a/lib/Slic3r/GCode.pm +++ b/lib/Slic3r/GCode.pm @@ -14,6 +14,8 @@ has 'enable_loop_clipping' => (is => 'rw', default => sub {1}); has 'enable_wipe' => (is => 'lazy'); # at least one extruder has wipe enabled has 'layer_count' => (is => 'ro', required => 1 ); has 'layer' => (is => 'rw'); +has '_layer_islands' => (is => 'rw'); +has '_upper_layer_islands' => (is => 'rw'); has '_layer_overhangs' => (is => 'rw'); has 'move_z_callback' => (is => 'rw'); has 'shift_x' => (is => 'rw', default => sub {0} ); @@ -98,7 +100,14 @@ sub change_layer { $self->layer($layer); - # avoid computing overhangs if they're not needed + # avoid computing islands and overhangs if they're not needed + if ($self->config->only_retract_when_crossing_perimeters) { + $self->_layer_islands([ $layer->islands ]); + $self->_upper_layer_islands([ $layer->upper_layer_islands ]); + } else { + $self->_layer_islands([]); + $self->_upper_layer_islands([]); + } $self->_layer_overhangs( $layer->id > 0 && ($Slic3r::Config->overhangs || $Slic3r::Config->start_perimeters_at_non_overhang) ? [ map $_->expolygon, grep $_->surface_type == S_TYPE_BOTTOM, map @{$_->slices}, @{$layer->regions} ] @@ -374,9 +383,9 @@ sub travel_to { # *and* in an island in the upper layer (so that the ooze will not be visible) if ($travel->length < scale $self->extruder->retract_before_travel || ($self->config->only_retract_when_crossing_perimeters - && (first { $_->encloses_line($travel, scaled_epsilon) } @{$self->layer->upper_layer_slices}) - && (first { $_->encloses_line($travel, scaled_epsilon) } @{$self->layer->slices})) - || ($role == EXTR_ROLE_SUPPORTMATERIAL && $self->layer->support_islands_enclose_line($travel)) + && (first { $_->encloses_line($travel, scaled_epsilon) } @{$self->_upper_layer_islands}) + && (first { $_->encloses_line($travel, scaled_epsilon) } @{$self->_layer_islands})) + || ($role == EXTR_ROLE_SUPPORTMATERIAL && (first { $_->encloses_line($travel, scaled_epsilon) } @{$self->layer->support_islands})) ) { $self->straight_once(0); $self->speed('travel'); diff --git a/lib/Slic3r/Layer.pm b/lib/Slic3r/Layer.pm index d1bc2818b5..a1b56b9177 100644 --- a/lib/Slic3r/Layer.pm +++ b/lib/Slic3r/Layer.pm @@ -23,11 +23,16 @@ sub _trigger_id { $_->_trigger_layer for @{$self->regions || []}; } -sub upper_layer_slices { +sub islands { + my $self = shift; + return @{$self->slices}; +} + +sub upper_layer_islands { my $self = shift; - my $upper_layer = $self->object->layers->[ $self->id + 1 ] or return []; - return $upper_layer->slices; + my $upper_layer = $self->object->layers->[ $self->id + 1 ] or return (); + return $upper_layer->islands; } sub region { @@ -56,20 +61,18 @@ sub make_perimeters { $_->make_perimeters for @{$self->regions}; } -sub support_islands_enclose_line { - my $self = shift; - my ($line) = @_; - return 0 if !$self->support_islands; # why can we arrive here if there are no support islands? - return (first { $_->encloses_line($line) } @{$self->support_islands}) ? 1 : 0; -} - package Slic3r::Layer::Support; use Moo; extends 'Slic3r::Layer'; # ordered collection of extrusion paths to fill surfaces for support material -has 'support_islands' => (is => 'rw'); +has 'support_islands' => (is => 'rw', default => sub { [] }); has 'support_fills' => (is => 'rw'); has 'support_interface_fills' => (is => 'rw'); +sub islands { + my $self = shift; + return @{$self->slices}, @{$self->support_islands}; +} + 1; diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index 1ca8ef38eb..ac75f542c4 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -682,7 +682,7 @@ sub make_brim { # -0.5 because islands are not represented by their centerlines # (first offset more, then step back - reverse order than the one used for # perimeters because here we're offsetting outwards) - push @loops, offset2(\@islands, ($i + 1.0) * $flow->scaled_spacing, -1.5 * $flow->scaled_spacing, undef, JT_SQUARE); + push @loops, offset2(\@islands, ($i + 0.5) * $flow->scaled_spacing, -1.0 * $flow->scaled_spacing, undef, JT_SQUARE); } @{$self->brim} = map Slic3r::ExtrusionLoop->pack( diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index 6ad1777158..524716f47b 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -1192,6 +1192,7 @@ sub generate_support_material { my $support_collection = Slic3r::ExtrusionPath::Collection->new(paths => $result->{support}); $layer->support_fills($support_collection) if @{$support_collection->paths} > 0; + # TODO: use a Slic3r::ExPolygon::Collection $layer->support_islands($result->{islands}); }; Slic3r::parallelize( From 3751e3813c76b88be7c1d0fbe89b0cad568a7c0c Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Fri, 9 Aug 2013 16:18:21 +0200 Subject: [PATCH 07/25] Fix regression causing too much collapsing of infill regions --- lib/Slic3r/Layer/Region.pm | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/Slic3r/Layer/Region.pm b/lib/Slic3r/Layer/Region.pm index df45b1ffec..d773a9d036 100644 --- a/lib/Slic3r/Layer/Region.pm +++ b/lib/Slic3r/Layer/Region.pm @@ -175,6 +175,7 @@ sub make_perimeters { # (one more than necessary so that we can detect gaps even after the desired # number of perimeters has been generated) my @last = @{$surface->expolygon}; + my @this_gaps = (); for my $i (0 .. $loop_number) { # external loop only needs half inset distance my $spacing = ($i == 0) @@ -195,7 +196,7 @@ sub make_perimeters { # won't shrink the clip polygon to be smaller than intended. [ offset(\@offsets, +0.5*$spacing + 2) ], ); - push @gaps, grep $_->area >= $gap_area_threshold, @$diff; + push @gaps, (@this_gaps = grep $_->area >= $gap_area_threshold, @$diff); } last if !@offsets || $i == $loop_number; @@ -204,15 +205,19 @@ sub make_perimeters { @last = @offsets; } + # make sure we don't infill narrow parts that are already gap-filled + # (we only consider this surface's gaps to reduce the diff() complexity) + @last = @{diff(\@last, [ map @$_, @this_gaps ])}; + # create one more offset to be used as boundary for fill # we offset by half the perimeter spacing (to get to the actual infill boundary) - # and then we offset back and forth by the infill spacing to only consider the + # and then we offset back and forth by half the infill spacing to only consider the # non-collapsing regions push @{ $self->fill_surfaces }, offset2_ex( [ map $_->simplify_as_polygons(&Slic3r::SCALED_RESOLUTION), @{union_ex(\@last)} ], - -($perimeter_spacing/2 + $infill_spacing), - +$infill_spacing, + -($perimeter_spacing/2 + $infill_spacing/2), + +$infill_spacing/2, ); } From b956faa1535ec9a4258034525e827a2a4af6dd42 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Fri, 9 Aug 2013 16:30:40 +0200 Subject: [PATCH 08/25] Adapt avoid_crossing_perimeters code to the recent changes --- lib/Slic3r/GCode.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Slic3r/GCode.pm b/lib/Slic3r/GCode.pm index 53e8715519..6c58b2dbb5 100644 --- a/lib/Slic3r/GCode.pm +++ b/lib/Slic3r/GCode.pm @@ -427,9 +427,9 @@ sub _plan { my $need_retract = !$self->config->only_retract_when_crossing_perimeters; if (!$need_retract) { $need_retract = 1; - foreach my $slice (@{$self->layer->upper_layer_slices}) { + foreach my $island ($self->layer->upper_layer_islands) { # discard the island if at any line is not enclosed in it - next if first { !$slice->encloses_line($_, scaled_epsilon) } @travel; + next if first { !$island->encloses_line($_, scaled_epsilon) } @travel; # okay, this island encloses the full travel path $need_retract = 0; last; From 548b3014321c8a6e6efbbe68dc589bdcca6a0f40 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Fri, 9 Aug 2013 16:34:55 +0200 Subject: [PATCH 09/25] Offset projection of facets before the final union --- lib/Slic3r/TriangleMesh.pm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/Slic3r/TriangleMesh.pm b/lib/Slic3r/TriangleMesh.pm index c2e543467e..5aa97c9a08 100644 --- a/lib/Slic3r/TriangleMesh.pm +++ b/lib/Slic3r/TriangleMesh.pm @@ -563,7 +563,9 @@ sub horizontal_projection { } $_->make_counter_clockwise for @f; # do this after scaling, as winding order might change while doing that - return union_ex(\@f, 1); + + # the offset factor was tuned using groovemount.stl + return union_ex([ offset(\@f, Slic3r::Geometry::scale 0.01) ], 1); } 1; From 4862d832b535d0bfe0235f124621cddf0a8bca9f Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Fri, 9 Aug 2013 19:46:20 +0200 Subject: [PATCH 10/25] Simplify layer change code now that we have distinct support layers --- lib/Slic3r/GCode.pm | 4 ++-- lib/Slic3r/GCode/Layer.pm | 24 ++++++------------------ lib/Slic3r/Print.pm | 6 +++++- 3 files changed, 13 insertions(+), 21 deletions(-) diff --git a/lib/Slic3r/GCode.pm b/lib/Slic3r/GCode.pm index 6c58b2dbb5..873479ec54 100644 --- a/lib/Slic3r/GCode.pm +++ b/lib/Slic3r/GCode.pm @@ -17,7 +17,6 @@ has 'layer' => (is => 'rw'); has '_layer_islands' => (is => 'rw'); has '_upper_layer_islands' => (is => 'rw'); has '_layer_overhangs' => (is => 'rw'); -has 'move_z_callback' => (is => 'rw'); has 'shift_x' => (is => 'rw', default => sub {0} ); has 'shift_y' => (is => 'rw', default => sub {0} ); has 'z' => (is => 'rw'); @@ -132,6 +131,8 @@ sub change_layer { $gcode .= $self->set_acceleration($self->config->default_acceleration); } } + + $gcode .= $self->move_z($layer->print_z); return $gcode; } @@ -153,7 +154,6 @@ sub move_z { $self->speed('travel'); $gcode .= $self->G0(undef, $z, 0, $comment || ('move to next layer (' . $self->layer->id . ')')) if !defined $self->z || abs($z - ($self->z - $self->lifted)) > epsilon; - $gcode .= $self->move_z_callback->() if defined $self->move_z_callback; } elsif ($z < $self->z && $z > ($self->z - $self->lifted + epsilon)) { # we're moving to a layer height which is greater than the nominal current one # (nominal = actual - lifted) and less than the actual one. we're basically diff --git a/lib/Slic3r/GCode/Layer.pm b/lib/Slic3r/GCode/Layer.pm index 307ab0e32e..1b21b3fca8 100644 --- a/lib/Slic3r/GCode/Layer.pm +++ b/lib/Slic3r/GCode/Layer.pm @@ -46,23 +46,16 @@ sub process_layer { $self->second_layer_things_done(1); } - # set new layer, but don't move Z as support material contact areas may need an intermediate one + # set new layer - this will change Z and force a retraction if retract_layer_change is enabled $gcode .= $self->gcodegen->change_layer($layer); - - # prepare callback to call as soon as a Z command is generated - $self->gcodegen->move_z_callback(sub { - $self->gcodegen->move_z_callback(undef); # circular ref or not? - return "" if !$Slic3r::Config->layer_gcode; - return $Slic3r::Config->replace_options($Slic3r::Config->layer_gcode, { - layer_num => $self->gcodegen->layer->id, - }) . "\n"; - }); + $gcode .= $Slic3r::Config->replace_options($Slic3r::Config->layer_gcode, { + layer_num => $self->gcodegen->layer->id, + }) . "\n" if $Slic3r::Config->layer_gcode; # extrude skirt if ((values %{$self->skirt_done}) < $Slic3r::Config->skirt_height && !$self->skirt_done->{$layer->print_z}) { $self->gcodegen->set_shift(@{$self->shift}); - $gcode .= $self->gcodegen->set_extruder($self->extruders->[0]); # move_z requires extruder - $gcode .= $self->gcodegen->move_z($layer->print_z); + $gcode .= $self->gcodegen->set_extruder($self->extruders->[0]); # skip skirt if we have a large brim if ($layer->id < $Slic3r::Config->skirt_height) { # distribute skirt loops across all extruders @@ -81,8 +74,7 @@ sub process_layer { # extrude brim if (!$self->brim_done) { - $gcode .= $self->gcodegen->set_extruder($self->extruders->[$Slic3r::Config->support_material_extruder-1]); # move_z requires extruder - $gcode .= $self->gcodegen->move_z($layer->print_z); + $gcode .= $self->gcodegen->set_extruder($self->extruders->[$Slic3r::Config->support_material_extruder-1]); $self->gcodegen->set_shift(@{$self->shift}); $gcode .= $self->gcodegen->extrude_loop($_, 'brim') for @{$self->print->brim}; $self->brim_done(1); @@ -98,7 +90,6 @@ sub process_layer { # extrude support material before other things because it might use a lower Z # and also because we avoid travelling on other things when printing it if ($self->print->has_support_material && $layer->isa('Slic3r::Layer::Support')) { - $gcode .= $self->gcodegen->move_z($layer->print_z); if ($layer->support_interface_fills) { $gcode .= $self->gcodegen->set_extruder($self->extruders->[$Slic3r::Config->support_material_interface_extruder-1]); $gcode .= $self->gcodegen->extrude_path($_, 'support material interface') @@ -111,9 +102,6 @@ sub process_layer { } } - # set actual Z - this will force a retraction - $gcode .= $self->gcodegen->move_z($layer->print_z); - # tweak region ordering to save toolchanges my @region_ids = 0 .. ($self->print->regions_count-1); if ($self->gcodegen->multiple_extruders) { diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index ac75f542c4..5448519154 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -732,7 +732,7 @@ sub write_gcode { # set up our extruder object my $gcodegen = Slic3r::GCode->new( config => $self->config, - extruders => $self->extruders, + extruders => $self->extruders, # we should only pass the *used* extruders (but maintain the Tx indices right!) layer_count => $self->layer_count, ); print $fh "G21 ; set units to millimeters\n" if $Slic3r::Config->gcode_flavor ne 'makerware'; @@ -768,6 +768,10 @@ sub write_gcode { } } + # always start with first extruder + # TODO: make sure we select the first *used* extruder + print $fh $gcodegen->set_extruder($self->extruders->[0]); + # calculate X,Y shift to center print around specified origin my $print_bb = $self->bounding_box; my $print_size = $print_bb->size; From abb5d1256f956e91dc249f219c3fc6f5d2d0f077 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Fri, 9 Aug 2013 21:27:57 +0200 Subject: [PATCH 11/25] Added some debugging code --- lib/Slic3r/Print/Object.pm | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index 524716f47b..547a6b8df4 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -914,6 +914,14 @@ sub generate_support_material { $contact{$contact_z} = [ @contact ]; $overhang{$contact_z} = [ @overhang ]; + + if (0) { + require "Slic3r/SVG.pm"; + Slic3r::SVG::output("contact_" . $layer->print_z . ".svg", + expolygons => union_ex(\@contact), + red_expolygons => \@overhang, + ); + } } } my @contact_z = sort keys %contact; From 5380b6cb33255ed07d0891701edc9b812d758bf0 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Sat, 10 Aug 2013 19:39:35 +0200 Subject: [PATCH 12/25] Incomplete work to improve support material by avoiding thin columns and making sure everything is supported correctly --- lib/Slic3r/Print/Object.pm | 85 +++++++++++++++++++++++++++----------- lib/Slic3r/SVG.pm | 2 +- 2 files changed, 61 insertions(+), 26 deletions(-) diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index 547a6b8df4..6d8c3fac8a 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -917,7 +917,7 @@ sub generate_support_material { if (0) { require "Slic3r/SVG.pm"; - Slic3r::SVG::output("contact_" . $layer->print_z . ".svg", + Slic3r::SVG::output("contact_" . $contact_z . ".svg", expolygons => union_ex(\@contact), red_expolygons => \@overhang, ); @@ -971,7 +971,7 @@ sub generate_support_material { my $z = $support_layers[$layer_id]; my $this = $contact{$z} // next; # count contact layer as interface layer - for (my $i = $layer_id; $i >= 0 && $i > $layer_id-$interface_layers; $i--) { + for (my $i = $layer_id-1; $i >= 0 && $i > $layer_id-$interface_layers; $i--) { $z = $support_layers[$i]; # Compute interface area on this layer as diff of upper contact area # (or upper interface area) and layer slices. @@ -985,6 +985,7 @@ sub generate_support_material { ], [ @{ $top{$z} || [] }, + @{ $contact{$z} || [] }, ], 1, ); @@ -1003,6 +1004,7 @@ sub generate_support_material { [ @{ $top{$z} || [] }, @{ $interface{$i} || [] }, + @{ $contact{$z} || [] }, ], 1, ); @@ -1043,11 +1045,20 @@ sub generate_support_material { my ($layer_id) = @_; my $result = { contact => [], interface => [], support => [] }; + if (0) { + require "Slic3r/SVG.pm"; + Slic3r::SVG::output("layer_" . $support_layers[$layer_id] . ".svg", + red_expolygons => union_ex($contact{$support_layers[$layer_id]} || []), + green_expolygons => union_ex($interface{$layer_id} || []), + ); + } + $contact{$layer_id} ||= []; $interface{$layer_id} ||= []; $support{$layer_id} ||= []; # contact + my $contact_infill = []; if ((my $contact = $contact{$support_layers[$layer_id]}) && $contact_loops > 0) { my $overhang = $overhang{$support_layers[$layer_id]}; $contact = [ grep $_->is_counter_clockwise, @$contact ]; @@ -1080,11 +1091,8 @@ sub generate_support_material { [ map Slic3r::Polygon->new(@$_)->split_at_first_point, @loops ], ) }; - # subtract loops from the contact area to detect the remaining part - $interface{$layer_id} = intersection( - $interface{$layer_id}, - [ offset2(\@loops0, -($contact_loops) * $flow->scaled_spacing, +0.5*$flow->scaled_spacing) ], - ); + # add the contact infill area to the interface area + $contact_infill = [ offset2(\@loops0, -($contact_loops) * $flow->scaled_spacing, +0.5*$flow->scaled_spacing) ]; # transform loops into ExtrusionPath objects @loops = map Slic3r::ExtrusionPath->pack( @@ -1096,13 +1104,40 @@ sub generate_support_material { $result->{contact} = [ @loops ]; } - # interface - if (@{$interface{$layer_id}}) { + # draw a perimeter around interface and support + { + # TODO: use brim ordering algorithm + my $contour = union([ map @$_, $interface{$layer_id}, $support{$layer_id} ], undef, 1); + push @{$result->{support}}, map Slic3r::ExtrusionPath->pack( + polyline => $_->split_at_first_point, + role => EXTR_ROLE_SUPPORTMATERIAL, + height => undef, + flow_spacing => $flow->spacing, + ), map Slic3r::Polygon->new(@$_), + offset2($contour, -$flow->scaled_spacing, +$flow->scaled_spacing*0.5); + + # subtract the perimeter area from both interface and support + my $to_remove = diff( + $contour, + [ offset($contour, -$flow->scaled_spacing) ], + ); + $interface{$layer_id} = diff( + $interface{$layer_id}, + $to_remove, + ); + $support{$layer_id} = diff( + $support{$layer_id}, + $to_remove, + ); + } + + # interface and contact infill + if (@{$interface{$layer_id}} || @$contact_infill) { $fillers{interface}->angle($interface_angle); # steal some space from support $interface{$layer_id} = intersection( - [ offset($interface{$layer_id}, scale 3) ], + [ offset([ map @$_, $interface{$layer_id}, $contact_infill ], scale 3) ], [ @{$interface{$layer_id}}, @{$support{$layer_id}} ], ); $support{$layer_id} = diff( @@ -1111,7 +1146,7 @@ sub generate_support_material { ); my @paths = (); - foreach my $expolygon (offset_ex($interface{$layer_id}, -$flow->scaled_width/2)) { + foreach my $expolygon (@{union_ex($interface{$layer_id})}) { my @p = $fillers{interface}->fill_surface( Slic3r::Surface->new(expolygon => $expolygon), density => $interface_density, @@ -1138,7 +1173,7 @@ sub generate_support_material { my $flow_spacing = $flow->spacing; # TODO: use offset2_ex() - my $to_infill = [ offset_ex(union($support{$layer_id}), -$flow->scaled_width/2) ]; + my $to_infill = union_ex($support{$layer_id}, undef, 1); my @paths = (); # base flange @@ -1147,18 +1182,6 @@ sub generate_support_material { $filler->angle($Slic3r::Config->support_material_angle + 90); $density = 0.5; $flow_spacing = $self->print->first_layer_support_material_flow->spacing; - } else { - # draw a perimeter all around support infill - # TODO: use brim ordering algorithm - push @paths, map Slic3r::ExtrusionPath->pack( - polyline => $_->split_at_first_point, - role => EXTR_ROLE_SUPPORTMATERIAL, - height => undef, - flow_spacing => $flow->spacing, - ), map @$_, @$to_infill; - - # TODO: use offset2_ex() - $to_infill = [ offset_ex([ map @$_, @$to_infill ], -$flow->scaled_spacing) ]; } foreach my $expolygon (@$to_infill) { @@ -1178,15 +1201,27 @@ sub generate_support_material { ), @p; } - $result->{support} = [ @paths ]; + push @{$result->{support}}, @paths; } # islands $result->{islands} = union_ex([ @{$interface{$layer_id} || []}, @{$support{$layer_id} || []}, + @{$contact{$support_layers[$layer_id]} || []}, ]); + if (0) { + require "Slic3r/SVG.pm"; + Slic3r::SVG::output("islands_" . $support_layers[$layer_id] . ".svg", + red_expolygons => union_ex($contact{$support_layers[$layer_id]} || []), + green_expolygons => union_ex($interface{$layer_id} || []), + red_polylines => [ map $_->unpack->polyline, @{$result->{contact}} ], + green_polylines => [ map $_->unpack->polyline, @{$result->{interface}} ], + polylines => [ map $_->unpack->polyline, @{$result->{support}} ], + ); + } + return $result; }; diff --git a/lib/Slic3r/SVG.pm b/lib/Slic3r/SVG.pm index 0ac2863951..b72aa229f7 100644 --- a/lib/Slic3r/SVG.pm +++ b/lib/Slic3r/SVG.pm @@ -57,7 +57,7 @@ sub output { } } - foreach my $type (qw(polygons polylines white_polygons green_polygons red_polygons red_polylines)) { + foreach my $type (qw(polygons polylines white_polygons green_polygons red_polygons red_polylines green_polylines)) { if ($things{$type}) { my $method = $type =~ /polygons/ ? 'polygon' : 'polyline'; my ($colour) = $type =~ /^(red|green)_/; From 5f07d39509fe302c4b27d2e6a7046ee5ad6ec33c Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Sat, 10 Aug 2013 21:30:50 +0200 Subject: [PATCH 13/25] Reapply perimeter only to support --- lib/Slic3r/Print/Object.pm | 39 ++++++++++++-------------------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index 6d8c3fac8a..1dfcec0be7 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -1104,33 +1104,6 @@ sub generate_support_material { $result->{contact} = [ @loops ]; } - # draw a perimeter around interface and support - { - # TODO: use brim ordering algorithm - my $contour = union([ map @$_, $interface{$layer_id}, $support{$layer_id} ], undef, 1); - push @{$result->{support}}, map Slic3r::ExtrusionPath->pack( - polyline => $_->split_at_first_point, - role => EXTR_ROLE_SUPPORTMATERIAL, - height => undef, - flow_spacing => $flow->spacing, - ), map Slic3r::Polygon->new(@$_), - offset2($contour, -$flow->scaled_spacing, +$flow->scaled_spacing*0.5); - - # subtract the perimeter area from both interface and support - my $to_remove = diff( - $contour, - [ offset($contour, -$flow->scaled_spacing) ], - ); - $interface{$layer_id} = diff( - $interface{$layer_id}, - $to_remove, - ); - $support{$layer_id} = diff( - $support{$layer_id}, - $to_remove, - ); - } - # interface and contact infill if (@{$interface{$layer_id}} || @$contact_infill) { $fillers{interface}->angle($interface_angle); @@ -1182,6 +1155,18 @@ sub generate_support_material { $filler->angle($Slic3r::Config->support_material_angle + 90); $density = 0.5; $flow_spacing = $self->print->first_layer_support_material_flow->spacing; + } else { + # draw a perimeter all around support infill + # TODO: use brim ordering algorithm + push @paths, map Slic3r::ExtrusionPath->pack( + polyline => $_->split_at_first_point, + role => EXTR_ROLE_SUPPORTMATERIAL, + height => undef, + flow_spacing => $flow->spacing, + ), map @$_, @$to_infill; + + # TODO: use offset2_ex() + $to_infill = [ offset_ex([ map @$_, @$to_infill ], -$flow->scaled_spacing) ]; } foreach my $expolygon (@$to_infill) { From 8d413eda443b3d25702dacf715a9afaa281d23c8 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Sun, 11 Aug 2013 19:25:51 +0200 Subject: [PATCH 14/25] Refactoring: generate interface and support in different cycles --- lib/Slic3r/Print/Object.pm | 39 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index 1dfcec0be7..e14c8fb5d3 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -961,15 +961,13 @@ sub generate_support_material { # if we wanted to apply some special logic to the first support layers lying on # object's top surfaces this is the place to detect them - # Let's now determine shells (interface layers) and normal support below them. - # Let's now fill each support layer by generating shells (interface layers) and - # clipping support area to the actual object boundaries. + # let's now generate interface layers below contact areas my %interface = (); # layer_id => [ polygons ] - my %support = (); # layer_id => [ polygons ] my $interface_layers = $Slic3r::Config->support_material_interface_layers; for my $layer_id (0 .. $#support_layers) { my $z = $support_layers[$layer_id]; my $this = $contact{$z} // next; + # count contact layer as interface layer for (my $i = $layer_id-1; $i >= 0 && $i > $layer_id-$interface_layers; $i--) { $z = $support_layers[$i]; @@ -980,31 +978,32 @@ sub generate_support_material { # surfaces before performing the diff, but this needs investigation. $this = $interface{$i} = diff( [ - @$this, - @{ $interface{$i} || [] }, + @$this, # clipped projection of the current contact regions + @{ $interface{$i} || [] }, # interface regions already applied to this layer ], [ - @{ $top{$z} || [] }, - @{ $contact{$z} || [] }, + @{ $top{$z} || [] }, # top slices on this layer + @{ $contact{$z} || [] }, # contact regions on this layer ], 1, ); } - - # determine what layers does our support belong to - for (my $i = $layer_id-$interface_layers; $i >= 0; $i--) { - $z = $support_layers[$i]; - # Compute support area on this layer as diff of upper support area - # and layer slices. - $this = $support{$i} = diff( + } + + # let's now generate support layers under interface layers + my %support = (); # layer_id => [ polygons ] + { + for my $i (reverse 0 .. $#support_layers-1) { + my $z = $support_layers[$i]; + $support{$i} = diff( [ - @$this, - @{ $support{$i} || [] }, + @{ $support{$i+1} || [] }, # support regions on upper layer + @{ $interface{$i+1} || [] }, # interface regions on upper layer ], [ - @{ $top{$z} || [] }, - @{ $interface{$i} || [] }, - @{ $contact{$z} || [] }, + @{ $top{$z} || [] }, # top slices on this layer + @{ $interface{$i} || [] }, # interface regions on this layer + @{ $contact{$z} || [] }, # contact regions on this layer ], 1, ); From 7062d028d285e9c2aa44f8feb4d7d014df529452 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Mon, 12 Aug 2013 18:12:53 +0200 Subject: [PATCH 15/25] Bugfix: top layers were not detected correctly, causing overlap of support material and object in some situations where there were contact regions having the same Z as some top regions --- lib/Slic3r/Print/Object.pm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index e14c8fb5d3..d9b23b7ac6 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -938,7 +938,9 @@ sub generate_support_material { # ('new' means all the areas that are lower than the last top layer # we considered) my $min_top = min(keys %top) // max(keys %contact); - push @$projection, map @{$contact{$_}}, grep { $_ > $layer->print_z && $_ < $min_top } keys %contact; + # use <= instead of just < because otherwise we'd ignore any contact regions + # having the same Z of top layers + push @$projection, map @{$contact{$_}}, grep { $_ > $layer->print_z && $_ <= $min_top } keys %contact; # now find whether any projection falls onto this top surface my $touching = intersection($projection, [ map $_->p, @top ]); From ca7d4163d7fb4f71436a4c7b6361385f948f44f3 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Mon, 12 Aug 2013 18:45:03 +0200 Subject: [PATCH 16/25] Remove jitter and overlaps in interface infill --- lib/Slic3r/Print/Object.pm | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index d9b23b7ac6..a61166a49d 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -1113,6 +1113,7 @@ sub generate_support_material { $interface{$layer_id} = intersection( [ offset([ map @$_, $interface{$layer_id}, $contact_infill ], scale 3) ], [ @{$interface{$layer_id}}, @{$support{$layer_id}} ], + undef, 1, ); $support{$layer_id} = diff( $support{$layer_id}, From 9513fa7600615c925841003efa8fc1c095b42ebc Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Mon, 12 Aug 2013 18:55:11 +0200 Subject: [PATCH 17/25] Enforce some horizontal margin between object and interface/support (contact not affected) --- lib/Slic3r/Print/Object.pm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index a61166a49d..29208af130 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -945,7 +945,10 @@ sub generate_support_material { # now find whether any projection falls onto this top surface my $touching = intersection($projection, [ map $_->p, @top ]); if (@$touching) { - $top{ $layer->print_z } = $touching; + # grow top surfaces so that interface and support generation are generated + # with some spacing from object - it looks we don't need the actual + # top shapes so this can be done here + $top{ $layer->print_z } = [ offset($touching, $flow->scaled_spacing) ]; } # remove the areas that touched from the projection that will continue on From e5fe04ea7a2c2aa607ac2f27851579259f1a5c23 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Mon, 12 Aug 2013 19:10:40 +0200 Subject: [PATCH 18/25] Make sure teeth are not too tight --- lib/Slic3r/Print/Object.pm | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index 29208af130..8e2e847c4e 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -826,14 +826,10 @@ sub generate_support_material { } # shape of contact area - my $contact_loops = 1; - my $circle_distance = 3 * $flow->scaled_width; - my $circle; - { - # TODO: make sure teeth between circles are compatible with support material flow - my $r = 1.5 * $flow->scaled_width; - $circle = Slic3r::Polygon->new(map [ $r * cos $_, $r * sin $_ ], (5*PI/3, 4*PI/3, PI, 2*PI/3, PI/3, 0)); - } + my $contact_loops = 1; + my $circle_radius = 1.5 * $flow->scaled_width; + my $circle_distance = 3 * $circle_radius; + my $circle = Slic3r::Polygon->new(map [ $circle_radius * cos $_, $circle_radius * sin $_ ], (5*PI/3, 4*PI/3, PI, 2*PI/3, PI/3, 0)); # determine contact areas my %contact = (); # contact_z => [ polygons ] From f1922ce7b31713aba915de5acdb1ea0db489770b Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Mon, 12 Aug 2013 19:19:22 +0200 Subject: [PATCH 19/25] Fix regression causing lack of contact infill --- lib/Slic3r/Print/Object.pm | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index 8e2e847c4e..8431640428 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -1043,19 +1043,27 @@ sub generate_support_material { my $process_layer = sub { my ($layer_id) = @_; - my $result = { contact => [], interface => [], support => [] }; + + $contact{$support_layers[$layer_id]} ||= []; + $interface{$layer_id} ||= []; + $support{$layer_id} ||= []; if (0) { require "Slic3r/SVG.pm"; Slic3r::SVG::output("layer_" . $support_layers[$layer_id] . ".svg", - red_expolygons => union_ex($contact{$support_layers[$layer_id]} || []), - green_expolygons => union_ex($interface{$layer_id} || []), + red_expolygons => union_ex($contact{$support_layers[$layer_id]}), + green_expolygons => union_ex($interface{$layer_id}), ); } - $contact{$layer_id} ||= []; - $interface{$layer_id} ||= []; - $support{$layer_id} ||= []; + # islands + my $result = { contact => [], interface => [], support => [] }; + $result->{islands} = union_ex([ + map @$_, + $interface{$layer_id}, + $support{$layer_id}, + $contact{$support_layers[$layer_id]}, + ]); # contact my $contact_infill = []; @@ -1092,7 +1100,7 @@ sub generate_support_material { ) }; # add the contact infill area to the interface area - $contact_infill = [ offset2(\@loops0, -($contact_loops) * $flow->scaled_spacing, +0.5*$flow->scaled_spacing) ]; + $contact_infill = [ offset2(\@loops0, -($contact_loops + 0.5) * $flow->scaled_spacing, +0.5*$flow->scaled_spacing) ]; # transform loops into ExtrusionPath objects @loops = map Slic3r::ExtrusionPath->pack( @@ -1111,7 +1119,7 @@ sub generate_support_material { # steal some space from support $interface{$layer_id} = intersection( [ offset([ map @$_, $interface{$layer_id}, $contact_infill ], scale 3) ], - [ @{$interface{$layer_id}}, @{$support{$layer_id}} ], + [ map @$_, $interface{$layer_id}, $support{$layer_id}, $contact_infill ], undef, 1, ); $support{$layer_id} = diff( @@ -1190,13 +1198,6 @@ sub generate_support_material { push @{$result->{support}}, @paths; } - # islands - $result->{islands} = union_ex([ - @{$interface{$layer_id} || []}, - @{$support{$layer_id} || []}, - @{$contact{$support_layers[$layer_id]} || []}, - ]); - if (0) { require "Slic3r/SVG.pm"; Slic3r::SVG::output("islands_" . $support_layers[$layer_id] . ".svg", From 36596bf569a2764f527ab80a26992039daed9c67 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Mon, 12 Aug 2013 20:27:25 +0200 Subject: [PATCH 20/25] Bugfix: alignment code for rectilinear infill caused lack of infill (regression in 948b43f). #1387 --- lib/Slic3r/Fill/Rectilinear.pm | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/Slic3r/Fill/Rectilinear.pm b/lib/Slic3r/Fill/Rectilinear.pm index 50567dc399..7e3745a96f 100644 --- a/lib/Slic3r/Fill/Rectilinear.pm +++ b/lib/Slic3r/Fill/Rectilinear.pm @@ -32,9 +32,8 @@ sub fill_surface { $flow_spacing = unscale $line_spacing; } else { # extend bounding box so that our pattern will be aligned with other layers - # $bounding_box->[X1] and [Y1] represent the displacement between new bounding box offset and old one - $bounding_box->extents->[X][MIN] -= $bounding_box->x_min; - $bounding_box->extents->[Y][MIN] -= $bounding_box->y_min; + $bounding_box->extents->[X][MIN] -= $bounding_box->x_min % $line_spacing; + $bounding_box->extents->[Y][MIN] -= $bounding_box->y_min % $line_spacing; } # generate the basic pattern From 2b36778dc19a75456cd380088a56d9f8ed682cb2 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Tue, 13 Aug 2013 09:45:33 +0200 Subject: [PATCH 21/25] Fix a situation where extra perimeters prevented top shell to be fully propagated. #1387 --- lib/Slic3r.pm | 1 + lib/Slic3r/Layer/Region.pm | 2 +- lib/Slic3r/Print/Object.pm | 12 +++++++++--- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/Slic3r.pm b/lib/Slic3r.pm index ad6157ec11..30654bed79 100644 --- a/lib/Slic3r.pm +++ b/lib/Slic3r.pm @@ -79,6 +79,7 @@ use constant OVERLAP_FACTOR => 1; use constant SMALL_PERIMETER_LENGTH => (6.5 / SCALING_FACTOR) * 2 * PI; use constant LOOP_CLIPPING_LENGTH_OVER_SPACING => 0.15; use constant INFILL_OVERLAP_OVER_SPACING => 0.45; +use constant EXTERNAL_INFILL_MARGIN => 3; our $Config; diff --git a/lib/Slic3r/Layer/Region.pm b/lib/Slic3r/Layer/Region.pm index d773a9d036..aa758a8626 100644 --- a/lib/Slic3r/Layer/Region.pm +++ b/lib/Slic3r/Layer/Region.pm @@ -416,7 +416,7 @@ sub prepare_fill_surfaces { sub process_external_surfaces { my $self = shift; - my $margin = scale 3; # TODO: ensure this is greater than the total thickness of the perimeters + my $margin = scale &Slic3r::EXTERNAL_INFILL_MARGIN; my @bottom = (); foreach my $surface (grep $_->surface_type == S_TYPE_BOTTOM, @{$self->fill_surfaces}) { diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index 8431640428..99c73b4fff 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -572,6 +572,8 @@ sub discover_horizontal_shells { Slic3r::debugf "==> DISCOVERING HORIZONTAL SHELLS\n"; + my $margin = scale &Slic3r::EXTERNAL_INFILL_MARGIN; + for my $region_id (0 .. ($self->print->regions_count-1)) { for (my $i = 0; $i < $self->layer_count; $i++) { my $layerm = $self->layers->[$i]->regions->[$region_id]; @@ -584,9 +586,13 @@ sub discover_horizontal_shells { EXTERNAL: foreach my $type (S_TYPE_TOP, S_TYPE_BOTTOM) { # find slices of current type for current layer - # get both slices and fill_surfaces before the former contains the perimeters area - # and the latter contains the enlarged external surfaces - my $solid = [ map $_->expolygon, grep $_->surface_type == $type, @{$layerm->slices}, @{$layerm->fill_surfaces} ]; + # use slices instead of fill_surfaces because they also include the perimeter area + # which needs to be propagated in shells; we need to grow slices like we did for + # fill_surfaces though. Using both ungrown slices and grown fill_surfaces will + # not work in some situations, as there won't be any grown region in the perimeter + # area (this was seen in a model where the top layer had one extra perimeter, thus + # its fill_surfaces was thinner than the lower layer's infill) + my $solid = [ map $_->expolygon->offset_ex($margin), grep $_->surface_type == $type, @{$layerm->slices} ]; next if !@$solid; Slic3r::debugf "Layer %d has %s surfaces\n", $i, ($type == S_TYPE_TOP ? 'top' : 'bottom'); From dbe429cf73f82156b410752fa3ef033f94aaeafd Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Tue, 13 Aug 2013 10:05:40 +0200 Subject: [PATCH 22/25] Regression test for fix 36596bf569a2764f527ab80a26992039daed9c67. #1387 --- t/fill.t | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/t/fill.t b/t/fill.t index ca064fac3f..3f7bb227c5 100644 --- a/t/fill.t +++ b/t/fill.t @@ -2,7 +2,7 @@ use Test::More; use strict; use warnings; -plan tests => 32; +plan tests => 33; BEGIN { use FindBin; @@ -51,17 +51,21 @@ sub scale_points (@) { map [scale $_->[X], scale $_->[Y]], @_ } { my $test = sub { - my ($expolygon, $flow_spacing) = @_; + my ($expolygon, $flow_spacing, $angle, $density) = @_; my $filler = Slic3r::Fill::Rectilinear->new( bounding_box => $expolygon->bounding_box, - angle => 0, + angle => $angle // 0, ); my $surface = Slic3r::Surface->new( surface_type => S_TYPE_BOTTOM, expolygon => $expolygon, ); - my ($params, @paths) = $filler->fill_surface($surface, flow_spacing => $flow_spacing, density => 1); + my ($params, @paths) = $filler->fill_surface( + $surface, + flow_spacing => $flow_spacing, + density => $density // 1, + ); # check whether any part was left uncovered my @grown_paths = map Slic3r::Polyline->new(@$_)->grow(scale $params->{flow_spacing}/2), @paths; @@ -100,6 +104,9 @@ sub scale_points (@) { map [scale $_->[X], scale $_->[Y]], @_ } [[59515297,5422499],[59531249,5578697],[59695801,6123186],[59965713,6630228],[60328214,7070685],[60773285,7434379],[61274561,7702115],[61819378,7866770],[62390306,7924789],[62958700,7866744],[63503012,7702244],[64007365,7434357],[64449960,7070398],[64809327,6634999],[65082143,6123325],[65245005,5584454],[65266967,5422499],[66267307,5422499],[66269190,8310081],[66275379,17810072],[66277259,20697500],[65267237,20697500],[65245004,20533538],[65082082,19994444],[64811462,19488579],[64450624,19048208],[64012101,18686514],[63503122,18415781],[62959151,18251378],[62453416,18198442],[62390147,18197355],[62200087,18200576],[61813519,18252990],[61274433,18415918],[60768598,18686517],[60327567,19047892],[59963609,19493297],[59695865,19994587],[59531222,20539379],[59515153,20697500],[58502480,20697500],[58502480,5422499]] ); $test->($expolygon, 0.524341649025257); + + $expolygon = Slic3r::ExPolygon->new([ scale_points [0,0], [98,0], [98,10], [0,10] ]); + $test->($expolygon, 0.5, 45, 0.99); # non-solid infill } { From ef8ce1b5bac0c9def3a9055adc31d2991b4b8edd Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Tue, 13 Aug 2013 10:34:49 +0200 Subject: [PATCH 23/25] Improvements to SVG debug tools: honor input order and support all colours --- lib/Slic3r/SVG.pm | 98 ++++++++++++++++++----------------------------- 1 file changed, 38 insertions(+), 60 deletions(-) diff --git a/lib/Slic3r/SVG.pm b/lib/Slic3r/SVG.pm index b72aa229f7..5b4d0a19b8 100644 --- a/lib/Slic3r/SVG.pm +++ b/lib/Slic3r/SVG.pm @@ -34,33 +34,36 @@ sub svg { } sub output { - my ($filename, %things) = @_; + my ($filename, @things) = @_; my $svg = svg(); + my $arrows = 1; - foreach my $type (qw(expolygons red_expolygons green_expolygons)) { - next if !$things{$type}; - my ($colour) = $type =~ /^(red|green)_/; - my $g = $svg->group( - style => { - 'stroke-width' => 2, - 'stroke' => $colour || 'black', - 'fill' => ($type !~ /polygons/ ? 'none' : ($colour || 'grey')), - 'fill-type' => $filltype, - }, - ); - foreach my $expolygon (@{$things{$type}}) { - my $points = join ' ', map "M $_ z", map join(" ", reverse map $_->[0]*factor() . " " . $_->[1]*factor(), @$_), @$expolygon; - $g->path( - d => $points, + while (my $type = shift @things) { + my $value = shift @things; + + if ($type eq 'no_arrows') { + $arrows = 0; + } elsif ($type =~ /^(?:(.+?)_)?expolygons$/) { + my $colour = $1; + + my $g = $svg->group( + style => { + 'stroke-width' => 2, + 'stroke' => $colour || 'black', + 'fill' => ($type !~ /polygons/ ? 'none' : ($colour || 'grey')), + 'fill-type' => $filltype, + }, ); - } - } - - foreach my $type (qw(polygons polylines white_polygons green_polygons red_polygons red_polylines green_polylines)) { - if ($things{$type}) { - my $method = $type =~ /polygons/ ? 'polygon' : 'polyline'; - my ($colour) = $type =~ /^(red|green)_/; + foreach my $expolygon (@$value) { + my $points = join ' ', map "M $_ z", map join(" ", reverse map $_->[0]*factor() . " " . $_->[1]*factor(), @$_), @$expolygon; + $g->path( + d => $points, + ); + } + } elsif ($type =~ /^(?:(.+?)_)?(polygon|polyline)s$/) { + my ($colour, $method) = ($1, $2); + my $g = $svg->group( style => { 'stroke-width' => 2, @@ -68,7 +71,7 @@ sub output { 'fill' => ($type !~ /polygons/ ? 'none' : ($colour || 'grey')), }, ); - foreach my $polygon (@{$things{$type}}) { + foreach my $polygon (@$value) { my $path = $svg->get_path( 'x' => [ map($_->[X] * factor(), @$polygon) ], 'y' => [ map($_->[Y] * factor(), @$polygon) ], @@ -76,15 +79,13 @@ sub output { ); $g->$method( %$path, - 'marker-end' => $things{no_arrows} ? "" : "url(#endArrow)", + 'marker-end' => $arrows ? "" : "url(#endArrow)", ); } - } - } - - foreach my $type (qw(points red_points)) { - if ($things{$type}) { - my ($colour, $r) = $type eq 'points' ? ('black', 5) : ('red', 3); + } elsif ($type =~ /^(?:(.+?)_)?points$/) { + my $colour = $1; + my $r = $colour eq 'black' ? 5 : 3; + my $g = $svg->group( style => { 'stroke-width' => 2, @@ -92,25 +93,22 @@ sub output { 'fill' => $colour, }, ); - foreach my $point (@{$things{$type}}) { + foreach my $point (@$value) { $g->circle( cx => $point->[X] * factor(), cy => $point->[Y] * factor(), r => $r, ); } - } - } - - foreach my $type (qw(lines red_lines green_lines)) { - if ($things{$type}) { - my ($colour) = $type =~ /^(red|green)_/; + } elsif ($type =~ /^(?:(.+?)_)?lines$/) { + my $colour = $1; + my $g = $svg->group( style => { 'stroke-width' => 2, }, ); - foreach my $line (@{$things{$type}}) { + foreach my $line (@$value) { $g->line( x1 => $line->[0][X] * factor(), y1 => $line->[0][Y] * factor(), @@ -119,7 +117,7 @@ sub output { style => { 'stroke' => $colour || 'black', }, - 'marker-end' => $things{no_arrows} ? "" : "url(#endArrow)", + 'marker-end' => $arrows ? "" : "url(#endArrow)", ); } } @@ -128,26 +126,6 @@ sub output { write_svg($svg, $filename); } -sub output_points { - my ($print, $filename, $points, $red_points) = @_; - return output($print, $filename, points => $points, red_points => $red_points); -} - -sub output_polygons { - my ($print, $filename, $polygons) = @_; - return output($print, $filename, polygons => $polygons); -} - -sub output_polylines { - my ($print, $filename, $polylines) = @_; - return output($print, $filename, polylines => $polylines); -} - -sub output_lines { - my ($print, $filename, $lines) = @_; - return output($print, $filename, lines => $lines); -} - sub write_svg { my ($svg, $filename) = @_; From b5df61df2c6e8deec10ebd542a15524cdb588c57 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Tue, 13 Aug 2013 10:46:46 +0200 Subject: [PATCH 24/25] Update test now failing because of some numerical instability --- t/shells.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/shells.t b/t/shells.t index bd4b221c65..175260be69 100644 --- a/t/shells.t +++ b/t/shells.t @@ -83,7 +83,7 @@ use Slic3r::Test; $config->set('first_layer_speed', '100%'); # prevent speed alteration $config->set('layer_height', 0.4); $config->set('first_layer_height', '100%'); - $config->set('extrusion_width', 0.5); + $config->set('extrusion_width', 0.55); $config->set('bottom_solid_layers', 3); $config->set('top_solid_layers', 0); $config->set('solid_infill_speed', 99); From 314f377d7b4d1cfa349336d2435d144a25cdb7a4 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Tue, 13 Aug 2013 20:17:17 +0200 Subject: [PATCH 25/25] Debugging code --- lib/Slic3r/Fill.pm | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/Slic3r/Fill.pm b/lib/Slic3r/Fill.pm index 5da06753e3..e6949f97fa 100644 --- a/lib/Slic3r/Fill.pm +++ b/lib/Slic3r/Fill.pm @@ -128,6 +128,14 @@ sub make_fill { # add spacing between surfaces @surfaces = map $_->offset(-$distance_between_surfaces / 2 * &Slic3r::INFILL_OVERLAP_OVER_SPACING), @surfaces; + if (0) { + require "Slic3r/SVG.pm"; + Slic3r::SVG::output("fill_" . $layerm->print_z . ".svg", + expolygons => [ map $_->expolygon, grep !$_->is_solid, @surfaces ], + red_expolygons => [ map $_->expolygon, grep $_->is_solid, @surfaces ], + ); + } + my @fills = (); my @fills_ordering_points = (); SURFACE: foreach my $surface (@surfaces) {