From ee41345ab05ad53a4b2d62855575bcc6cc2bfb3c Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Thu, 23 Aug 2012 15:46:55 +0200 Subject: [PATCH 1/5] Remove useless Point->id method --- lib/Slic3r/Point.pm | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/Slic3r/Point.pm b/lib/Slic3r/Point.pm index ffa7fa1a87..cba2f1af9f 100644 --- a/lib/Slic3r/Point.pm +++ b/lib/Slic3r/Point.pm @@ -32,11 +32,6 @@ sub cast { } } -sub id { - my $self = shift; - return join ',', @$self; -} - sub coordinates { my $self = shift; return @$self; From 5281b101f9bac65a03eb35aa93eaff0fa4aa6895 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Fri, 24 Aug 2012 18:59:23 +0200 Subject: [PATCH 2/5] Some infill paths were still disconnected, causing unnecessary retractions --- lib/Slic3r/ExPolygon.pm | 12 ++++++++---- lib/Slic3r/Fill/Rectilinear.pm | 10 ++++++---- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/lib/Slic3r/ExPolygon.pm b/lib/Slic3r/ExPolygon.pm index 7037185519..5f9d23577b 100644 --- a/lib/Slic3r/ExPolygon.pm +++ b/lib/Slic3r/ExPolygon.pm @@ -6,7 +6,7 @@ use warnings; use Boost::Geometry::Utils; use Math::Geometry::Voronoi; -use Slic3r::Geometry qw(X Y A B point_in_polygon same_line); +use Slic3r::Geometry qw(X Y A B point_in_polygon same_line line_length); use Slic3r::Geometry::Clipper qw(union_ex JT_MITER); # the constructor accepts an array of polygons @@ -110,10 +110,14 @@ sub encloses_point_quick { sub encloses_line { my $self = shift; - my ($line) = @_; - + my ($line, $tolerance) = @_; my $clip = $self->clip_line($line); - return @$clip == 1 && same_line($clip->[0], $line); + if (!defined $tolerance) { + # optimization + return @$clip == 1 && same_line($clip->[0], $line); + } else { + return @$clip == 1 && abs(line_length($clip->[0]) - $line->length) < $tolerance; + } } sub point_on_segment { diff --git a/lib/Slic3r/Fill/Rectilinear.pm b/lib/Slic3r/Fill/Rectilinear.pm index ebfa316e8e..2de7872a6d 100644 --- a/lib/Slic3r/Fill/Rectilinear.pm +++ b/lib/Slic3r/Fill/Rectilinear.pm @@ -14,9 +14,8 @@ sub fill_surface { my $rotate_vector = $self->infill_direction($surface); $self->rotate_points($expolygon, $rotate_vector); - my ($expolygon_off) = $expolygon->offset_ex(scale 0.3); + my ($expolygon_off) = $expolygon->offset_ex(scale $params{flow_spacing}/2); return {} if !$expolygon_off; # skip some very small polygons (which shouldn't arrive here) - my ($expolygon_epsilon_off) = $expolygon->offset_ex(scale epsilon); my $bounding_box = [ $expolygon->bounding_box ]; my $min_spacing = scale $params{flow_spacing}; @@ -46,8 +45,11 @@ sub fill_surface { push @vertical_lines, $vertical_line; $x += $distance_between_lines; } + + # clip paths against a slightly offsetted expolygon, so that the first and last paths + # are kept even if the expolygon has vertical sides my @paths = @{ Boost::Geometry::Utils::polygon_linestring_intersection( - $expolygon_epsilon_off->boost_polygon, + +($expolygon->offset_ex(scale epsilon))[0]->boost_polygon, # TODO: we should use all the resulting expolygons and clip the linestrings to a multipolygon object Boost::Geometry::Utils::linestring(@vertical_lines), ) }; for (@paths) { @@ -78,7 +80,7 @@ sub fill_surface { # TODO: we should also check that both points are on a fill_boundary to avoid # connecting paths on the boundaries of internal regions if ($can_connect->(@distance, $paths[-1][-1], $path->points->[0]) - && $expolygon_off->encloses_line(Slic3r::Line->new($paths[-1][-1], $path->points->[0]))) { + && $expolygon_off->encloses_line(Slic3r::Line->new($paths[-1][-1], $path->points->[0]), $tolerance)) { push @{$paths[-1]}, @{$path->points}; next; } From ba58e0733fffaa39e6ca6babf69a91de194ee575 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Fri, 24 Aug 2012 19:19:45 +0200 Subject: [PATCH 3/5] Avoid backwards moves when doing honeycomb infill. #492 --- lib/Slic3r/Fill/Honeycomb.pm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/Slic3r/Fill/Honeycomb.pm b/lib/Slic3r/Fill/Honeycomb.pm index cbc4f61d39..229c725686 100644 --- a/lib/Slic3r/Fill/Honeycomb.pm +++ b/lib/Slic3r/Fill/Honeycomb.pm @@ -83,7 +83,10 @@ sub fill_surface { $self->cache->{$cache_id} = [@polygons]; } - my @paths = map Slic3r::Polyline->new(@$_, $_->[0]), map @$_, @{intersection_ex( + # build polylines from polygons without re-appending the initial point: + # this cuts the last segment on purpose, so that the jump to the next + # path is more straight + my @paths = map Slic3r::Polyline->new(@$_), map @$_, @{intersection_ex( $self->cache->{$cache_id}, [ map @$_, $expolygon->offset_ex($overlap_distance) ], )}; From 92518d28fc95d7eec73c141a0b8b7fa000896096 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Fri, 24 Aug 2012 19:38:36 +0200 Subject: [PATCH 4/5] New option to configure the threshold for enforcing solid infill. #224 --- README.markdown | 3 +++ lib/Slic3r/Config.pm | 8 ++++++++ lib/Slic3r/GUI/Tab.pm | 2 +- lib/Slic3r/Layer.pm | 2 +- slic3r.pl | 3 +++ 5 files changed, 16 insertions(+), 2 deletions(-) diff --git a/README.markdown b/README.markdown index fc5ce7f864..a335f0cb94 100644 --- a/README.markdown +++ b/README.markdown @@ -170,6 +170,9 @@ The author of the Silk icon set is Mark James. --layer-gcode Load layer-change G-code from the supplied file (default: nothing). --extra-perimeters Add more perimeters when needed (default: yes) --randomize-start Randomize starting point across layers (default: yes) + --solid-infill-below-area + Force solid infill when a region has a smaller area than this threshold + (mm^2, default: 70) Support material options: --support-material Generate support material for overhangs diff --git a/lib/Slic3r/Config.pm b/lib/Slic3r/Config.pm index 7af58122cd..36aaa5ae75 100644 --- a/lib/Slic3r/Config.pm +++ b/lib/Slic3r/Config.pm @@ -449,6 +449,14 @@ our $Options = { max => 359, default => 45, }, + 'solid_infill_below_area' => { + label => 'Solid infill threshold area', + tooltip => 'Force solid infill for regions having a smaller area than the specified threshold.', + sidetext => 'mm²', + cli => 'solid-infill-below-area=f', + type => 'f', + default => 70, + }, 'extra_perimeters' => { label => 'Generate extra perimeters when needed', cli => 'extra-perimeters!', diff --git a/lib/Slic3r/GUI/Tab.pm b/lib/Slic3r/GUI/Tab.pm index 111800e0aa..cd68593aee 100644 --- a/lib/Slic3r/GUI/Tab.pm +++ b/lib/Slic3r/GUI/Tab.pm @@ -401,7 +401,7 @@ sub build { }, { title => 'Advanced', - options => [qw(infill_every_layers fill_angle)], + options => [qw(infill_every_layers fill_angle solid_infill_below_area)], }, ]); diff --git a/lib/Slic3r/Layer.pm b/lib/Slic3r/Layer.pm index 2bd51d873d..9fa69482f8 100644 --- a/lib/Slic3r/Layer.pm +++ b/lib/Slic3r/Layer.pm @@ -365,7 +365,7 @@ sub prepare_fill_surfaces { # turn too small internal regions into solid regions { - my $min_area = ((7 * $self->infill_flow->spacing / &Slic3r::SCALING_FACTOR)**2) * PI; + my $min_area = scale scale $Slic3r::Config->solid_infill_below_area; # scaling an area requires two calls! my @small = grep $_->surface_type == S_TYPE_INTERNAL && $_->expolygon->contour->area <= $min_area, @surfaces; $_->surface_type(S_TYPE_INTERNALSOLID) for @small; Slic3r::debugf "identified %d small surfaces at layer %d\n", scalar(@small), $self->id if @small > 0; diff --git a/slic3r.pl b/slic3r.pl index a4f5ca4d19..0f9baa58c6 100755 --- a/slic3r.pl +++ b/slic3r.pl @@ -213,6 +213,9 @@ $j --layer-gcode Load layer-change G-code from the supplied file (default: nothing). --extra-perimeters Add more perimeters when needed (default: yes) --randomize-start Randomize starting point across layers (default: yes) + --solid-infill-below-area + Force solid infill when a region has a smaller area than this threshold + (mm^2, default: $config->{solid_infill_below_area}) Support material options: --support-material Generate support material for overhangs From 65b11fa850dcd4fee4096b6a09b6aea70dfcff0c Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Fri, 24 Aug 2012 21:58:51 +0200 Subject: [PATCH 5/5] Minor refactoring for better readability of perimeter generation logic --- lib/Slic3r/Layer.pm | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/lib/Slic3r/Layer.pm b/lib/Slic3r/Layer.pm index 9fa69482f8..fc33cf4209 100644 --- a/lib/Slic3r/Layer.pm +++ b/lib/Slic3r/Layer.pm @@ -191,7 +191,6 @@ sub make_perimeters { # for each island: foreach my $surface (@surfaces) { my @last_offsets = ($surface->expolygon); - my $distance = 0; # experimental hole compensation (see ArcCompensation in the RepRap wiki) if (0) { @@ -216,32 +215,29 @@ sub make_perimeters { } } + my $distance = scale $self->perimeter_flow->spacing; my @gaps = (); - # generate perimeters inwards + # generate perimeters inwards (loop 0 is the external one) my $loop_number = $Slic3r::Config->perimeters + ($surface->additional_inner_perimeters || 0); - push @perimeters, []; - for (my $loop = 0; $loop < $loop_number; $loop++) { + push @perimeters, [[@last_offsets]]; + for (my $loop = 1; $loop < $loop_number; $loop++) { # offsetting a polygon can result in one or many offset polygons - if ($distance) { - my @new_offsets = (); - foreach my $expolygon (@last_offsets) { - my @offsets = map $_->offset_ex(+0.5*$distance), $expolygon->offset_ex(-1.5*$distance); - push @new_offsets, @offsets; - - my $diff = diff_ex( - [ map @$_, $expolygon->offset_ex(-$distance) ], - [ map @$_, @offsets ], - ); - push @gaps, grep $_->area >= $gap_area_threshold, @$diff; - } - @last_offsets = @new_offsets; + my @new_offsets = (); + foreach my $expolygon (@last_offsets) { + my @offsets = map $_->offset_ex(+0.5*$distance), $expolygon->offset_ex(-1.5*$distance); + push @new_offsets, @offsets; + + my $diff = diff_ex( + [ map @$_, $expolygon->offset_ex(-$distance) ], + [ map @$_, @offsets ], + ); + push @gaps, grep $_->area >= $gap_area_threshold, @$diff; } + @last_offsets = @new_offsets; + last if !@last_offsets; push @{ $perimeters[-1] }, [@last_offsets]; - - # offset distance for inner loops - $distance = scale $self->perimeter_flow->spacing; } # create one more offset to be used as boundary for fill