From dc0f70678984c483cfd61e5eb4c85e648aeb7fa8 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Thu, 14 Mar 2013 14:27:08 +0100 Subject: [PATCH 1/6] Bugfix: simplification of support areas could lead to complex polygons with bad orientation, thus causing wrong pattern clipping. #1032 --- lib/Slic3r/ExPolygon.pm | 8 ++++++++ lib/Slic3r/Geometry/Clipper.pm | 11 ++++++++++- lib/Slic3r/Print/Object.pm | 5 ++++- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/lib/Slic3r/ExPolygon.pm b/lib/Slic3r/ExPolygon.pm index 770db9a8..202258ac 100644 --- a/lib/Slic3r/ExPolygon.pm +++ b/lib/Slic3r/ExPolygon.pm @@ -5,6 +5,7 @@ use warnings; # an ExPolygon is a polygon with holes use Boost::Geometry::Utils; +use List::Util qw(first); use Math::Geometry::Voronoi; use Slic3r::Geometry qw(X Y A B point_in_polygon same_line line_length epsilon); use Slic3r::Geometry::Clipper qw(union_ex JT_MITER); @@ -54,6 +55,13 @@ sub clipper_expolygon { }; } +sub is_valid { + my $self = shift; + return (!first { !$_->is_valid } @$self) + && $self->contour->is_counter_clockwise + && (!first { $_->is_counter_clockwise } $self->holes); +} + sub boost_polygon { my $self = shift; return Boost::Geometry::Utils::polygon(@$self); diff --git a/lib/Slic3r/Geometry/Clipper.pm b/lib/Slic3r/Geometry/Clipper.pm index 292e88f2..6b259e0b 100644 --- a/lib/Slic3r/Geometry/Clipper.pm +++ b/lib/Slic3r/Geometry/Clipper.pm @@ -4,7 +4,7 @@ use warnings; require Exporter; our @ISA = qw(Exporter); -our @EXPORT_OK = qw(safety_offset offset offset_ex +our @EXPORT_OK = qw(safety_offset offset offset_ex collapse_ex diff_ex diff union_ex intersection_ex xor_ex PFT_EVENODD JT_MITER JT_ROUND JT_SQUARE is_counter_clockwise); @@ -83,4 +83,13 @@ sub xor_ex { ]; } +sub collapse_ex { + my ($polygons, $width) = @_; + my @result = offset( + [ offset($polygons, -$width/2,) ], + +$width/2, + ); + return union_ex([@result]); +} + 1; diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index 6008e02e..947daee5 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -4,7 +4,7 @@ use Moo; use List::Util qw(min sum first); use Slic3r::ExtrusionPath ':roles'; use Slic3r::Geometry qw(Z PI scale unscale deg2rad rad2deg scaled_epsilon); -use Slic3r::Geometry::Clipper qw(diff_ex intersection_ex union_ex offset); +use Slic3r::Geometry::Clipper qw(diff_ex intersection_ex union_ex offset collapse_ex); use Slic3r::Surface ':types'; has 'print' => (is => 'ro', weak_ref => 1, required => 1); @@ -774,6 +774,7 @@ sub generate_support_material { [ map @$_, @{ $upper_layers_overhangs[-1] || [] } ], [ map @$_, @current_layer_offsetted_slices ], ); + $layers_contact_areas{$i} = collapse_ex([ map @$_, @{$layers_contact_areas{$i}} ], $flow->scaled_width); $_->simplify($flow->scaled_spacing) for @{$layers_contact_areas{$i}}; # to define interface regions of this layer we consider the overhangs of all the upper layers @@ -785,6 +786,7 @@ sub generate_support_material { (map @$_, @{ $layers_contact_areas{$i} }), ], ); + $layers_interfaces{$i} = collapse_ex([ map @$_, @{$layers_interfaces{$i}} ], $flow->scaled_width); $_->simplify($flow->scaled_spacing) for @{$layers_interfaces{$i}}; # generate support material in current layer (for upper layers) @@ -804,6 +806,7 @@ sub generate_support_material { (map @$_, @{ $layers_interfaces{$i} }), ], ); + $layers{$i} = collapse_ex([ map @$_, @{$layers{$i}} ], $flow->scaled_width); $_->simplify($flow->scaled_spacing) for @{$layers{$i}}; # get layer overhangs and put them into queue for adding support inside lower layers; From 33b40eda1848c757b8e659c722683f9c10d35d9f Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Sat, 16 Mar 2013 18:42:56 +0100 Subject: [PATCH 2/6] Always fix self-intersecting polygons that Douglas-Peucker might return --- lib/Slic3r/ExPolygon.pm | 9 +++++++-- lib/Slic3r/ExtrusionPath.pm | 5 +++++ lib/Slic3r/GCode/MotionPlanner.pm | 16 +++++++--------- lib/Slic3r/GUI/Plater.pm | 3 +-- lib/Slic3r/Geometry.pm | 11 +---------- lib/Slic3r/Geometry/Clipper.pm | 10 ++++++++++ lib/Slic3r/Layer/Region.pm | 16 ++++++++-------- lib/Slic3r/Polygon.pm | 5 +++++ lib/Slic3r/Polyline.pm | 4 ++-- lib/Slic3r/Print.pm | 4 ++-- lib/Slic3r/Print/Object.pm | 18 ++++++++++++------ lib/Slic3r/Surface.pm | 22 ++++++++++++++++------ t/clean_polylines.t | 13 +++++++------ t/combineinfill.t | 4 ++-- 14 files changed, 85 insertions(+), 55 deletions(-) diff --git a/lib/Slic3r/ExPolygon.pm b/lib/Slic3r/ExPolygon.pm index 202258ac..558f9fe2 100644 --- a/lib/Slic3r/ExPolygon.pm +++ b/lib/Slic3r/ExPolygon.pm @@ -172,8 +172,13 @@ sub clip_line { sub simplify { my $self = shift; - $_->simplify(@_) for @$self; - $self; + my ($tolerance) = @_; + + # it would be nice to have a multilinestring_simplify method in B::G::U + my @simplified = Slic3r::Geometry::Clipper::simplify_polygons( + [ map Boost::Geometry::Utils::linestring_simplify($_, $tolerance), @$self ], + ); + return @{ Slic3r::Geometry::Clipper::union_ex([ @simplified ]) }; } sub scale { diff --git a/lib/Slic3r/ExtrusionPath.pm b/lib/Slic3r/ExtrusionPath.pm index 825d23e6..3de63964 100644 --- a/lib/Slic3r/ExtrusionPath.pm +++ b/lib/Slic3r/ExtrusionPath.pm @@ -81,6 +81,11 @@ sub clip_with_expolygon { return @paths; } +sub simplify { + my $self = shift; + $self->polyline($self->polyline->simplify(@_)); +} + sub points { my $self = shift; return $self->polyline; diff --git a/lib/Slic3r/GCode/MotionPlanner.pm b/lib/Slic3r/GCode/MotionPlanner.pm index d55faeb2..3708a65e 100644 --- a/lib/Slic3r/GCode/MotionPlanner.pm +++ b/lib/Slic3r/GCode/MotionPlanner.pm @@ -56,22 +56,20 @@ sub BUILD { } }; + # simplify islands + @{$self->islands} = map $_->simplify($self->_inner_margin), @{$self->islands}; + # process individual islands - for my $i (0 .. $#{$self->islands}) { - # simplify the island's contours - $self->islands->[$i]->simplify($self->_inner_margin); - + for my $i (0 .. $#{$self->islands}) { # offset the island inwards to make the boundaries for internal movements # so that no motion along external perimeters happens - $self->_inner->[$i] = [ $self->islands->[$i]->offset_ex(-$self->_inner_margin) ] - if !$self->no_internal; + $self->_inner->[$i] = $self->no_internal + ? [] + : [ $self->islands->[$i]->offset_ex(-$self->_inner_margin) ]; # offset the island outwards to make the boundaries for external movements $self->_outer->[$i] = [ $self->islands->[$i]->contour->offset($self->_outer_margin) ]; - # further simplification (isn't this a duplication of the one above?) - $_->simplify($self->_inner_margin) for @{$self->_inner->[$i]}, @{$self->_outer->[$i]}; - # if internal motion is enabled, build a set of utility expolygons representing # the outer boundaries (as contours) and the inner boundaries (as holes). whenever # we jump from a hole to a contour or viceversa, we know we're crossing a perimeter diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index 3b86a597..0cdd5d04 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -1137,9 +1137,8 @@ sub make_thumbnail { for (map @$_, map @$_, @{$thumbnail->expolygons}) { @$_ = map $_ * $self->thumbnail_scaling_factor, @$_; } + @{$thumbnail->expolygons} = map $_->simplify(0.5), grep $_->area >= 1, @{$thumbnail->expolygons}; foreach my $expolygon (@{$thumbnail->expolygons}) { - @$expolygon = grep $_->area >= 1, @$expolygon; - $expolygon->simplify(0.5); $expolygon->rotate(Slic3r::Geometry::deg2rad($self->rotate)); $expolygon->scale($self->scale); } diff --git a/lib/Slic3r/Geometry.pm b/lib/Slic3r/Geometry.pm index 6a91a204..0d2d9df4 100644 --- a/lib/Slic3r/Geometry.pm +++ b/lib/Slic3r/Geometry.pm @@ -12,7 +12,7 @@ our @EXPORT_OK = qw( point_is_on_left_of_segment polyline_lines polygon_lines nearest_point point_along_segment polygon_segment_having_point polygon_has_subsegment polygon_has_vertex polyline_length can_connect_points deg2rad rad2deg - rotate_points move_points remove_coinciding_points clip_segment_polygon + rotate_points move_points clip_segment_polygon sum_vectors multiply_vector subtract_vectors dot perp polygon_points_visibility line_intersection bounding_box bounding_box_intersect same_point same_line longest_segment angle3points three_points_aligned line_direction @@ -375,15 +375,6 @@ sub move_points { return map Slic3r::Point->new($shift->[X] + $_->[X], $shift->[Y] + $_->[Y]), @points; } -# preserves order -sub remove_coinciding_points { - my ($points) = @_; - - my %p = map { sprintf('%f,%f', @$_) => "$_" } @$points; - %p = reverse %p; - @$points = grep $p{"$_"}, @$points; -} - # implementation of Liang-Barsky algorithm # polygon must be convex and ccw sub clip_segment_polygon { diff --git a/lib/Slic3r/Geometry/Clipper.pm b/lib/Slic3r/Geometry/Clipper.pm index 6b259e0b..0cc78b18 100644 --- a/lib/Slic3r/Geometry/Clipper.pm +++ b/lib/Slic3r/Geometry/Clipper.pm @@ -92,4 +92,14 @@ sub collapse_ex { return union_ex([@result]); } +sub simplify_polygon { + my ($polygon, $pft) = @_; + return @{ Math::Clipper::simplify_polygon($polygon, $pft // PFT_NONZERO) }; +} + +sub simplify_polygons { + my ($polygons, $pft) = @_; + return @{ Math::Clipper::simplify_polygons($polygons, $pft // PFT_NONZERO) }; +} + 1; diff --git a/lib/Slic3r/Layer/Region.pm b/lib/Slic3r/Layer/Region.pm index a3b6abe0..99bdbfc1 100644 --- a/lib/Slic3r/Layer/Region.pm +++ b/lib/Slic3r/Layer/Region.pm @@ -263,14 +263,14 @@ sub make_perimeters { # 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 # non-collapsing regions - my @fill_boundaries = @{union_ex([ - Slic3r::Geometry::Clipper::offset( - [Slic3r::Geometry::Clipper::offset([ map @$_, @last_offsets ], -($perimeter_spacing/2 + $infill_spacing))], - +$infill_spacing, - ), - ])}; - $_->simplify(&Slic3r::SCALED_RESOLUTION) for @fill_boundaries; - push @{ $self->fill_surfaces }, @fill_boundaries; + push @{ $self->fill_surfaces }, + map $_->simplify(&Slic3r::SCALED_RESOLUTION), + @{union_ex([ + Slic3r::Geometry::Clipper::offset( + [Slic3r::Geometry::Clipper::offset([ map @$_, @last_offsets ], -($perimeter_spacing/2 + $infill_spacing))], + +$infill_spacing, + ), + ])}; } # fill gaps diff --git a/lib/Slic3r/Polygon.pm b/lib/Slic3r/Polygon.pm index f5b27551..1d759a06 100644 --- a/lib/Slic3r/Polygon.pm +++ b/lib/Slic3r/Polygon.pm @@ -97,6 +97,11 @@ sub grow { return $self->split_at_first_point->grow(@_); } +sub simplify { + my $self = shift; + return Slic3r::Geometry::Clipper::simplify_polygon( $self->SUPER::simplify(@_) ); +} + # this method subdivides the polygon segments to that no one of them # is longer than the length provided sub subdivide { diff --git a/lib/Slic3r/Polyline.pm b/lib/Slic3r/Polyline.pm index 63103060..2578e505 100644 --- a/lib/Slic3r/Polyline.pm +++ b/lib/Slic3r/Polyline.pm @@ -68,8 +68,8 @@ sub simplify { my $self = shift; my $tolerance = shift || 10; - @$self = @{ Boost::Geometry::Utils::linestring_simplify($self, $tolerance) }; - bless $_, 'Slic3r::Point' for @$self; + my $simplified = Boost::Geometry::Utils::linestring_simplify($self, $tolerance); + return (ref $self)->new($simplified); } sub reverse { diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index e69ed756..075b4edc 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -335,8 +335,8 @@ sub export_gcode { # simplify slices (both layer and region slices), # we only need the max resolution for perimeters foreach my $layer (map @{$_->layers}, @{$self->objects}) { - $_->simplify(&Slic3r::SCALED_RESOLUTION) - for @{$layer->slices}, (map $_->expolygon, map @{$_->slices}, @{$layer->regions}); + @$_ = map $_->simplify(&Slic3r::SCALED_RESOLUTION), @$_ + for $layer->slices, (map $_->slices, @{$layer->regions}); } # this will assign a type (top/bottom/internal) to $layerm->slices diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index 947daee5..51527d0f 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -774,8 +774,10 @@ sub generate_support_material { [ map @$_, @{ $upper_layers_overhangs[-1] || [] } ], [ map @$_, @current_layer_offsetted_slices ], ); - $layers_contact_areas{$i} = collapse_ex([ map @$_, @{$layers_contact_areas{$i}} ], $flow->scaled_width); - $_->simplify($flow->scaled_spacing) for @{$layers_contact_areas{$i}}; + $layers_contact_areas{$i} = [ + map $_->simplify($flow->scaled_spacing), + collapse_ex([ map @$_, @{$layers_contact_areas{$i}} ], $flow->scaled_width), + ]; # to define interface regions of this layer we consider the overhangs of all the upper layers # minus the first one @@ -786,8 +788,10 @@ sub generate_support_material { (map @$_, @{ $layers_contact_areas{$i} }), ], ); - $layers_interfaces{$i} = collapse_ex([ map @$_, @{$layers_interfaces{$i}} ], $flow->scaled_width); - $_->simplify($flow->scaled_spacing) for @{$layers_interfaces{$i}}; + $layers_interfaces{$i} = [ + map $_->simplify($flow->scaled_spacing), + collapse_ex([ map @$_, @{$layers_interfaces{$i}} ], $flow->scaled_width), + ]; # generate support material in current layer (for upper layers) @current_support_regions = @{diff_ex( @@ -806,8 +810,10 @@ sub generate_support_material { (map @$_, @{ $layers_interfaces{$i} }), ], ); - $layers{$i} = collapse_ex([ map @$_, @{$layers{$i}} ], $flow->scaled_width); - $_->simplify($flow->scaled_spacing) for @{$layers{$i}}; + $layers{$i} = [ + map $_->simplify($flow->scaled_spacing), + collapse_ex([ map @$_, @{$layers{$i}} ], $flow->scaled_width), + ]; # get layer overhangs and put them into queue for adding support inside lower layers; # we need an angle threshold for this diff --git a/lib/Slic3r/Surface.pm b/lib/Slic3r/Surface.pm index 2864a864..2272c6d3 100644 --- a/lib/Slic3r/Surface.pm +++ b/lib/Slic3r/Surface.pm @@ -81,12 +81,22 @@ sub group { sub offset { my $self = shift; - return map { - (ref $self)->new( - expolygon => $_, - map { $_ => $self->$_ } qw(surface_type depth_layers bridge_angle), - ) - } $self->expolygon->offset_ex(@_); + return map $self->_inflate_expolygon($_), $self->expolygon->offset_ex(@_); +} + +sub simplify { + my $self = shift; + return map $self->_inflate_expolygon($_), $self->expolygon->simplify(@_); +} + +sub _inflate_expolygon { + my $self = shift; + my ($expolygon) = @_; + + return (ref $self)->new( + expolygon => $expolygon, + map { $_ => $self->$_ } qw(surface_type depth_layers bridge_angle), + ); } sub clipper_polygon { diff --git a/t/clean_polylines.t b/t/clean_polylines.t index 064b7bd3..9f7b3ce2 100644 --- a/t/clean_polylines.t +++ b/t/clean_polylines.t @@ -2,7 +2,7 @@ use Test::More; use strict; use warnings; -plan tests => 6; +plan tests => 7; BEGIN { use FindBin; @@ -24,7 +24,7 @@ use Slic3r; my $polyline = Slic3r::Polyline->new([ [0,0],[1,0],[2,0],[2,1],[2,2],[1,2],[0,2],[0,1],[0,0], ]); - $polyline->simplify(1); + $polyline = $polyline->simplify(1); is_deeply $polyline, [ [0, 0], [2, 0], [2, 2], [0, 2], [0, 0] ], 'Douglas-Peucker'; } @@ -33,7 +33,7 @@ use Slic3r; [0,0],[0.5,0.5],[1,0],[1.25,-0.25],[1.5,.5], ]); $polyline->scale(100); - $polyline->simplify(25); + $polyline = $polyline->simplify(25); is_deeply $polyline, [ [0, 0], [50, 50], [125, -25], [150, 50] ], 'Douglas-Peucker'; } @@ -75,9 +75,10 @@ use Slic3r; ok @$polygon < @$gear, 'gear was simplified using merge_continuous_lines'; my $num_points = scalar @$polygon; - $polygon->simplify; - note sprintf "original points: %d\nnew points: %d", $num_points, scalar(@$polygon); - ok @$polygon < $num_points, 'gear was further simplified using Douglas-Peucker'; + my @simplified = $polygon->simplify; + ok @simplified == 1, 'gear simplified to a single polygon'; + note sprintf "original points: %d\nnew points: %d", $num_points, scalar(@{$simplified[0]}); + ok @{$simplified[0]} < $num_points, 'gear was further simplified using Douglas-Peucker'; } { diff --git a/t/combineinfill.t b/t/combineinfill.t index e2e63f4a..f5f54fa8 100644 --- a/t/combineinfill.t +++ b/t/combineinfill.t @@ -43,8 +43,8 @@ use Slic3r::Test; $_->slice(keep_meshes => 1) for @{$self->objects}; $_->make_perimeters for @{$self->objects}; foreach my $layer (map @{$_->layers}, @{$self->objects}) { - $_->simplify(&Slic3r::SCALED_RESOLUTION) - for @{$layer->slices}, (map $_->expolygon, map @{$_->slices}, @{$layer->regions}); + @$_ = map $_->simplify(&Slic3r::SCALED_RESOLUTION), @$_ + for $layer->slices, (map $_->slices, @{$layer->regions}); } $_->detect_surfaces_type for @{$self->objects}; $_->prepare_fill_surfaces for map @{$_->regions}, map @{$_->layers}, @{$self->objects}; From db2e76a0df1d030b48fa66d44f384dffd2bd4802 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Sat, 16 Mar 2013 18:56:49 +0100 Subject: [PATCH 3/6] New option to change perimeter order. #534 --- README.markdown | 1 + lib/Slic3r/Config.pm | 7 +++++++ lib/Slic3r/GUI/Tab.pm | 2 +- lib/Slic3r/Layer/Region.pm | 8 ++++++-- slic3r.pl | 1 + 5 files changed, 16 insertions(+), 3 deletions(-) diff --git a/README.markdown b/README.markdown index 5015e231..df651b6a 100644 --- a/README.markdown +++ b/README.markdown @@ -197,6 +197,7 @@ The author of the Silk icon set is Mark James. --extra-perimeters Add more perimeters when needed (default: yes) --randomize-start Randomize starting point across layers (default: yes) --avoid-crossing-perimeters Optimize travel moves so that no perimeters are crossed (default: no) + --external-perimeters-first Reverse perimeter order. (default: no) --only-retract-when-crossing-perimeters Disable retraction when travelling between infill paths inside the same island. (default: yes) diff --git a/lib/Slic3r/Config.pm b/lib/Slic3r/Config.pm index 0017d925..454afd40 100644 --- a/lib/Slic3r/Config.pm +++ b/lib/Slic3r/Config.pm @@ -562,6 +562,13 @@ our $Options = { type => 'bool', default => 0, }, + 'external_perimeters_first' => { + label => 'External perimeters first', + tooltip => 'Print contour perimeters from the outermost one to the innermost one instead of the default inverse order.', + cli => 'external-perimeters-first!', + type => 'bool', + default => 0, + }, 'only_retract_when_crossing_perimeters' => { label => 'Only retract when crossing perimeters', tooltip => 'Disables retraction when travelling between infill paths inside the same island.', diff --git a/lib/Slic3r/GUI/Tab.pm b/lib/Slic3r/GUI/Tab.pm index 35637c88..79f9af96 100644 --- a/lib/Slic3r/GUI/Tab.pm +++ b/lib/Slic3r/GUI/Tab.pm @@ -407,7 +407,7 @@ sub build { }, { title => 'Advanced', - options => [qw(avoid_crossing_perimeters)], + options => [qw(avoid_crossing_perimeters external_perimeters_first)], }, ]); diff --git a/lib/Slic3r/Layer/Region.pm b/lib/Slic3r/Layer/Region.pm index 99bdbfc1..1c365dd4 100644 --- a/lib/Slic3r/Layer/Region.pm +++ b/lib/Slic3r/Layer/Region.pm @@ -404,10 +404,14 @@ sub make_perimeters { } } - # do holes, then contours starting from innermost one + # first do holes $self->_add_perimeter($holes[$_], $is_external{$_} ? EXTR_ROLE_EXTERNAL_PERIMETER : undef) for reverse 0 .. $#holes; - for my $depth (reverse 0 .. $#$island) { + + # then do contours according to the user settings + my @contour_order = 0 .. $#$island; + @contour_order = reverse @contour_order if !$Slic3r::Config->external_perimeters_first; + for my $depth (@contour_order) { my $role = $depth == $#$island ? EXTR_ROLE_CONTOUR_INTERNAL_PERIMETER : $depth == 0 ? EXTR_ROLE_EXTERNAL_PERIMETER : EXTR_ROLE_PERIMETER; diff --git a/slic3r.pl b/slic3r.pl index 301c6b85..4290ceb8 100755 --- a/slic3r.pl +++ b/slic3r.pl @@ -250,6 +250,7 @@ $j --extra-perimeters Add more perimeters when needed (default: yes) --randomize-start Randomize starting point across layers (default: yes) --avoid-crossing-perimeters Optimize travel moves so that no perimeters are crossed (default: no) + --external-perimeters-first Reverse perimeter order. (default: no) --only-retract-when-crossing-perimeters Disable retraction when travelling between infill paths inside the same island. (default: no) From f4b81856988456984f71457367696557e2a8c6f3 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Sat, 16 Mar 2013 19:11:49 +0100 Subject: [PATCH 4/6] Fixed typo preventing support material to work with new simplify() syntax --- lib/Slic3r/Print/Object.pm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index 51527d0f..6ab07bd6 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -776,7 +776,7 @@ sub generate_support_material { ); $layers_contact_areas{$i} = [ map $_->simplify($flow->scaled_spacing), - collapse_ex([ map @$_, @{$layers_contact_areas{$i}} ], $flow->scaled_width), + @{collapse_ex([ map @$_, @{$layers_contact_areas{$i}} ], $flow->scaled_width)}, ]; # to define interface regions of this layer we consider the overhangs of all the upper layers @@ -790,7 +790,7 @@ sub generate_support_material { ); $layers_interfaces{$i} = [ map $_->simplify($flow->scaled_spacing), - collapse_ex([ map @$_, @{$layers_interfaces{$i}} ], $flow->scaled_width), + @{collapse_ex([ map @$_, @{$layers_interfaces{$i}} ], $flow->scaled_width)}, ]; # generate support material in current layer (for upper layers) @@ -812,7 +812,7 @@ sub generate_support_material { ); $layers{$i} = [ map $_->simplify($flow->scaled_spacing), - collapse_ex([ map @$_, @{$layers{$i}} ], $flow->scaled_width), + @{collapse_ex([ map @$_, @{$layers{$i}} ], $flow->scaled_width)}, ]; # get layer overhangs and put them into queue for adding support inside lower layers; From 10b6bc9d15e8a284cb8c98abb6aadb8d5724e9fb Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Sat, 16 Mar 2013 19:39:00 +0100 Subject: [PATCH 5/6] Removed keep_meshes --- lib/Slic3r/Print.pm | 4 ++-- lib/Slic3r/Print/Object.pm | 2 +- t/combineinfill.t | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index 075b4edc..e5025cc0 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -324,7 +324,7 @@ sub export_gcode { # skein the STL into layers # each layer has surfaces with holes $status_cb->(10, "Processing triangulated mesh"); - $_->slice(keep_meshes => $params{keep_meshes}) for @{$self->objects}; + $_->slice for @{$self->objects}; # make perimeters # this will add a set of extrusion loops to each layer @@ -477,7 +477,7 @@ sub export_svg { # calls ->perimeter_flow $self->init_extruders; - $_->slice(keep_meshes => $params{keep_meshes}) for @{$self->objects}; + $_->slice for @{$self->objects}; $self->arrange_objects; my $output_file = $self->expanded_output_filepath($params{output_file}); diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index 6ab07bd6..3abc5c2d 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -121,7 +121,7 @@ sub slice { die "Invalid input file\n" if !@{$self->layers}; # free memory - $self->meshes(undef) unless $params{keep_meshes}; + $self->meshes(undef); # remove last layer if empty # (we might have created it because of the $max_layer = ... + 1 code in TriangleMesh) diff --git a/t/combineinfill.t b/t/combineinfill.t index f5f54fa8..77eabcc0 100644 --- a/t/combineinfill.t +++ b/t/combineinfill.t @@ -40,7 +40,7 @@ use Slic3r::Test; # copy of Print::export_gcode() up to the point # after fill surfaces are combined $self->init_extruders; - $_->slice(keep_meshes => 1) for @{$self->objects}; + $_->slice for @{$self->objects}; $_->make_perimeters for @{$self->objects}; foreach my $layer (map @{$_->layers}, @{$self->objects}) { @$_ = map $_->simplify(&Slic3r::SCALED_RESOLUTION), @$_ From cf5adca928d246802bc47bf3d4df648538ca80c3 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Sat, 16 Mar 2013 19:58:34 +0100 Subject: [PATCH 6/6] New --resolution option to simplify input models --- README.markdown | 1 + lib/Slic3r/Config.pm | 9 +++++++++ lib/Slic3r/GUI/Tab.pm | 6 +++--- lib/Slic3r/Print.pm | 20 ++++++++++++++++---- slic3r.pl | 1 + 5 files changed, 30 insertions(+), 7 deletions(-) diff --git a/README.markdown b/README.markdown index df651b6a..ffebd148 100644 --- a/README.markdown +++ b/README.markdown @@ -289,6 +289,7 @@ The author of the Silk icon set is Mark James. Miscellaneous options: --notes Notes to be added as comments to the output file + --resolution Minimum detail resolution (mm, set zero for full resolution, default: 0) Flow options (advanced): --extrusion-width Set extrusion width manually; it accepts either an absolute value in mm diff --git a/lib/Slic3r/Config.pm b/lib/Slic3r/Config.pm index 454afd40..1bd9657a 100644 --- a/lib/Slic3r/Config.pm +++ b/lib/Slic3r/Config.pm @@ -37,6 +37,15 @@ our $Options = { default => $Slic3r::have_threads ? 2 : 1, readonly => !$Slic3r::have_threads, }, + 'resolution' => { + label => 'Resolution', + tooltip => 'Minimum detail resolution, used to simplify the input file for speeding up the slicing job and reducing memory usage. High-resolution models often carry more detail than printers can render. Set to zero to disable any simplification and use full resolution from input.', + sidetext => 'mm', + cli => 'resolution=f', + type => 'f', + min => 0, + default => 0, + }, # output options 'output_filename_format' => { diff --git a/lib/Slic3r/GUI/Tab.pm b/lib/Slic3r/GUI/Tab.pm index 79f9af96..fa10383e 100644 --- a/lib/Slic3r/GUI/Tab.pm +++ b/lib/Slic3r/GUI/Tab.pm @@ -517,10 +517,10 @@ sub build { title => 'Flow', options => [qw(bridge_flow_ratio)], }, - $Slic3r::have_threads ? { + { title => 'Other', - options => [qw(threads)], - } : (), + options => [($Slic3r::have_threads ? qw(threads) : ()), qw(resolution)], + }, ]); } diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index e5025cc0..3be7fe87 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -313,6 +313,16 @@ sub size { return [ $bb[X2] - $bb[X1], $bb[Y2] - $bb[Y1] ]; } +sub _simplify_slices { + my $self = shift; + my ($distance) = @_; + + foreach my $layer (map @{$_->layers}, @{$self->objects}) { + @$_ = map $_->simplify($distance), @$_ + for $layer->slices, (map $_->slices, @{$layer->regions}); + } +} + sub export_gcode { my $self = shift; my %params = @_; @@ -326,6 +336,11 @@ sub export_gcode { $status_cb->(10, "Processing triangulated mesh"); $_->slice for @{$self->objects}; + if ($Slic3r::Config->resolution) { + $status_cb->(15, "Simplifying input"); + $self->_simplify_slices(scale $Slic3r::Config->resolution); + } + # make perimeters # this will add a set of extrusion loops to each layer # as well as generate infill boundaries @@ -334,10 +349,7 @@ sub export_gcode { # simplify slices (both layer and region slices), # we only need the max resolution for perimeters - foreach my $layer (map @{$_->layers}, @{$self->objects}) { - @$_ = map $_->simplify(&Slic3r::SCALED_RESOLUTION), @$_ - for $layer->slices, (map $_->slices, @{$layer->regions}); - } + $self->_simplify_slices(&Slic3r::SCALED_RESOLUTION); # this will assign a type (top/bottom/internal) to $layerm->slices # and transform $layerm->fill_surfaces from expolygon diff --git a/slic3r.pl b/slic3r.pl index 4290ceb8..c4cfd848 100755 --- a/slic3r.pl +++ b/slic3r.pl @@ -342,6 +342,7 @@ $j Miscellaneous options: --notes Notes to be added as comments to the output file + --resolution Minimum detail resolution (mm, set zero for full resolution, default: $config->{resolution}) Flow options (advanced): --extrusion-width Set extrusion width manually; it accepts either an absolute value in mm