Просмотр исходного кода

New seal_position option that replaces randomize_start, start_perimeters_at_concave_points and start_perimeters_at_non_overhang. The two latter options are now always on by default. A new "Aligned" seal position value has been added, that forces starting points to be aligned when not randomized. #1741 #925

Alessandro Ranellucci 10 лет назад
Родитель
Сommit
a3bd1b5302
10 измененных файлов с 86 добавлено и 84 удалено
  1. 1 5
      README.md
  2. 6 1
      lib/Slic3r/Config.pm
  3. 27 34
      lib/Slic3r/GCode.pm
  4. 2 6
      lib/Slic3r/GUI/Tab.pm
  5. 9 2
      lib/Slic3r/Layer/Region.pm
  6. 24 5
      lib/Slic3r/Polygon.pm
  7. 1 1
      lib/Slic3r/Polyline.pm
  8. 1 5
      slic3r.pl
  9. 3 25
      t/perimeters.t
  10. 12 0
      xs/src/MultiPoint.cpp

+ 1 - 5
README.md

@@ -219,7 +219,7 @@ The author of the Silk icon set is Mark James.
                             home X axis [G28 X], disable motors [M84]).
         --layer-gcode       Load layer-change G-code from the supplied file (default: nothing).
         --toolchange-gcode  Load tool-change G-code from the supplied file (default: nothing).
-        --randomize-start   Randomize starting point across layers (default: yes)
+        --seal-position     Position of loop starting points (random/nearest/aligned, default: aligned).
         --external-perimeters-first Reverse perimeter order. (default: no)
         --spiral-vase       Experimental option to raise Z gradually when printing single-walled vases
                             (default: no)
@@ -236,10 +236,6 @@ The author of the Silk icon set is Mark James.
        Quality options (slower slicing):
         --extra-perimeters  Add more perimeters when needed (default: yes)
         --avoid-crossing-perimeters Optimize travel moves so that no perimeters are crossed (default: no)
-        --start-perimeters-at-concave-points
-                            Try to start perimeters at concave points if any (default: no)
-        --start-perimeters-at-non-overhang
-                            Try to start perimeters at non-overhang points if any (default: no)
         --thin-walls        Detect single-width walls (default: yes)
         --overhangs         Experimental option to use bridge flow, speed and fan for overhangs
                             (default: yes)

+ 6 - 1
lib/Slic3r/Config.pm

@@ -8,7 +8,8 @@ use List::Util qw(first max);
 # cemetery of old config settings
 our @Ignore = qw(duplicate_x duplicate_y multiply_x multiply_y support_material_tool acceleration
     adjust_overhang_flow standby_temperature scale rotate duplicate duplicate_grid
-    rotate scale duplicate_grid);
+    rotate scale duplicate_grid start_perimeters_at_concave_points start_perimeters_at_non_overhang
+    randomize_start);
 
 our $Options = print_config_def();
 
@@ -140,6 +141,10 @@ sub _handle_legacy {
         $value *= 100;
         $value = "$value";  # force update of the PV value, workaround for bug https://rt.cpan.org/Ticket/Display.html?id=94110
     }
+    if ($opt_key eq 'randomize_start' && $value) {
+        $opt_key = 'seal_position';
+        $value = 'random';
+    }
     
     # For historical reasons, the world's full of configs having these very low values;
     # to avoid unexpected behavior we need to ignore them.  Banning these two hard-coded

+ 27 - 34
lib/Slic3r/GCode.pm

@@ -19,6 +19,7 @@ has '_layer_index'       => (is => 'rw', default => sub {-1});  # just a counter
 has 'layer'              => (is => 'rw');
 has '_layer_islands'     => (is => 'rw');
 has '_upper_layer_islands'  => (is => 'rw');
+has '_seal_position'     => (is => 'ro', default => sub { {} });  # $object => pos
 has 'shift_x'            => (is => 'rw', default => sub {0} );
 has 'shift_y'            => (is => 'rw', default => sub {0} );
 has 'z'                  => (is => 'rw');
@@ -150,45 +151,37 @@ sub extrude_loop {
     # extrude all loops ccw
     my $was_clockwise = $loop->make_counter_clockwise;
     
-    # find candidate starting points
-    # start looking for concave vertices not being overhangs
-    my $polygon = $loop->polygon;
-    my @concave = ();
-    if ($self->config->start_perimeters_at_concave_points) {
-        @concave = $polygon->concave_points;
-    }
-    my @candidates = ();
-    if ($self->config->start_perimeters_at_non_overhang) {
-        @candidates = grep !$loop->has_overhang_point($_), @concave;
-    }
-    if (!@candidates) {
-        # if none, look for any concave vertex
-        @candidates = @concave;
-        if (!@candidates) {
-            # if none, look for any non-overhang vertex
-            if ($self->config->start_perimeters_at_non_overhang) {
-                @candidates = grep !$loop->has_overhang_point($_), @$polygon;
-            }
-            if (!@candidates) {
-                # if none, all points are valid candidates
-                @candidates = @$polygon;
-            }
-        }
-    }
-    
     # find the point of the loop that is closest to the current extruder position
     # or randomize if requested
     my $last_pos = $self->last_pos;
-    if ($self->config->randomize_start && $loop->role == EXTRL_ROLE_CONTOUR_INTERNAL_PERIMETER) {
-        $last_pos = Slic3r::Point->new(scale $self->config->print_center->[X], scale $self->config->bed_size->[Y]);
-        $last_pos->rotate(rand(2*PI), $self->config->print_center);
-    }
-    
-    # split the loop at the starting point
     if ($self->config->spiral_vase) {
         $loop->split_at($last_pos);
-    } else {
-        $loop->split_at_vertex($last_pos->nearest_point(\@candidates));
+    } elsif ($self->config->seal_position eq 'nearest' || $self->config->seal_position eq 'aligned') {
+        my $polygon = $loop->polygon;
+        my @candidates = @{$polygon->concave_points(PI*4/3)};
+        @candidates = @{$polygon->convex_points(PI*2/3)} if !@candidates;
+        @candidates = @{$polygon} if !@candidates;
+        
+        my @non_overhang = grep !$loop->has_overhang_point($_), @candidates;
+        @candidates = @non_overhang if @non_overhang;
+        
+        if ($self->config->seal_position eq 'nearest') {
+            $loop->split_at_vertex($last_pos->nearest_point(\@candidates));
+        } elsif ($self->config->seal_position eq 'aligned') {
+            if (defined $self->layer && defined $self->_seal_position->{$self->layer->object}) {
+                $last_pos = $self->_seal_position->{$self->layer->object};
+            }
+            my $point = $self->_seal_position->{$self->layer->object} = $last_pos->nearest_point(\@candidates);
+            $loop->split_at_vertex($point);
+        }
+    } elsif ($self->config->seal_position eq 'random') {
+        if ($loop->role == EXTRL_ROLE_CONTOUR_INTERNAL_PERIMETER) {
+            my $polygon = $loop->polygon;
+            my $centroid = $polygon->centroid;
+            $last_pos = Slic3r::Point->new($polygon->bounding_box->x_max, $centroid->y);  #))
+            $last_pos->rotate(rand(2*PI), $centroid);
+        }
+        $loop->split_at($last_pos);
     }
     
     # clip the path to avoid the extruder to get exactly on the first point of the loop;

+ 2 - 6
lib/Slic3r/GUI/Tab.pm

@@ -417,21 +417,17 @@ sub build {
         },
         {
             title => 'Quality (slower slicing)',
-            options => [qw(extra_perimeters avoid_crossing_perimeters start_perimeters_at_concave_points start_perimeters_at_non_overhang thin_walls overhangs)],
+            options => [qw(extra_perimeters avoid_crossing_perimeters thin_walls overhangs)],
             lines => [
                 Slic3r::GUI::OptionsGroup->single_option_line('extra_perimeters'),
                 Slic3r::GUI::OptionsGroup->single_option_line('avoid_crossing_perimeters'),
-                {
-                    label   => 'Start perimeters at',
-                    options => [qw(start_perimeters_at_concave_points start_perimeters_at_non_overhang)],
-                },
                 Slic3r::GUI::OptionsGroup->single_option_line('thin_walls'),
                 Slic3r::GUI::OptionsGroup->single_option_line('overhangs'),
             ],
         },
         {
             title => 'Advanced',
-            options => [qw(randomize_start external_perimeters_first)],
+            options => [qw(seal_position external_perimeters_first)],
         },
     ]);
     

+ 9 - 2
lib/Slic3r/Layer/Region.pm

@@ -260,12 +260,19 @@ sub make_perimeters {
             
             my $role        = EXTR_ROLE_PERIMETER;
             my $loop_role   = EXTRL_ROLE_DEFAULT;
-            if ($is_contour ? $depth == 0 : !@{ $polynode->{children} }) {
+            
+            my $root_level  = $depth == 0;
+            my $no_children = !@{ $polynode->{children} };
+            my $is_external = $is_contour ? $root_level : $no_children;
+            my $is_internal = $is_contour ? $no_children : $root_level;
+            if ($is_external) {
                 # external perimeters are root level in case of contours
                 # and items with no children in case of holes
                 $role       = EXTR_ROLE_EXTERNAL_PERIMETER;
                 $loop_role  = EXTRL_ROLE_EXTERNAL_PERIMETER;
-            } elsif ($depth == 1 && $is_contour) {
+            } elsif ($is_contour && $is_internal) {
+                # internal perimeters are root level in case of holes
+                # and items with no children in case of contours
                 $loop_role  = EXTRL_ROLE_CONTOUR_INTERNAL_PERIMETER;
             }
             

+ 24 - 5
lib/Slic3r/Polygon.pm

@@ -40,15 +40,34 @@ sub subdivide {
     return Slic3r::Polygon->new(@new_points);
 }
 
-# for cw polygons this will return convex points!
+# angle is checked on the internal side of the polygon
 sub concave_points {
-    my $self = shift;
+    my ($self, $angle) = @_;
+    
+    $angle //= PI;
+    
+    my @points = @$self;
+    my @points_pp = @{$self->pp};
+    return [
+        map $points[$_],
+        grep Slic3r::Geometry::angle3points(@points_pp[$_, $_-1, $_+1]) < $angle,
+        -1 .. ($#points-1)
+    ];
+}
+
+# angle is checked on the internal side of the polygon
+sub convex_points {
+    my ($self, $angle) = @_;
+    
+    $angle //= PI;
     
     my @points = @$self;
     my @points_pp = @{$self->pp};
-    return map $points[$_],
-        grep Slic3r::Geometry::angle3points(@points_pp[$_, $_-1, $_+1]) < PI - epsilon,
-        -1 .. ($#points-1);
+    return [
+        map $points[$_],
+        grep Slic3r::Geometry::angle3points(@points_pp[$_, $_-1, $_+1]) > $angle,
+        -1 .. ($#points-1)
+    ];
 }
 
 1;

+ 1 - 1
lib/Slic3r/Polyline.pm

@@ -3,7 +3,7 @@ use strict;
 use warnings;
 
 use List::Util qw(first);
-use Slic3r::Geometry qw(X Y epsilon);
+use Slic3r::Geometry qw(X Y PI epsilon);
 use Slic3r::Geometry::Clipper qw(JT_SQUARE);
 
 sub new_scale {

+ 1 - 5
slic3r.pl

@@ -342,7 +342,7 @@ $j
                         home X axis [G28 X], disable motors [M84]).
     --layer-gcode       Load layer-change G-code from the supplied file (default: nothing).
     --toolchange-gcode  Load tool-change G-code from the supplied file (default: nothing).
-    --randomize-start   Randomize starting point across layers (default: yes)
+    --seal-position     Position of loop starting points (random/nearest/aligned, default: $config->{seal_position}).
     --external-perimeters-first Reverse perimeter order. (default: no)
     --spiral-vase       Experimental option to raise Z gradually when printing single-walled vases
                         (default: no)
@@ -359,10 +359,6 @@ $j
    Quality options (slower slicing):
     --extra-perimeters  Add more perimeters when needed (default: yes)
     --avoid-crossing-perimeters Optimize travel moves so that no perimeters are crossed (default: no)
-    --start-perimeters-at-concave-points
-                        Try to start perimeters at concave points if any (default: no)
-    --start-perimeters-at-non-overhang
-                        Try to start perimeters at non-overhang points if any (default: no)
     --thin-walls        Detect single-width walls (default: yes)
     --overhangs         Experimental option to use bridge flow, speed and fan for overhangs
                         (default: yes)

+ 3 - 25
t/perimeters.t

@@ -1,4 +1,4 @@
-use Test::More tests => 10;
+use Test::More tests => 9;
 use strict;
 use warnings;
 
@@ -85,28 +85,6 @@ use Slic3r::Test;
         ok !$has_outwards_move, 'move inwards after completing external loop';
     }
     
-    {
-        $config->set('start_perimeters_at_concave_points', 1);
-        my $print = Slic3r::Test::init_print('L', config => $config);
-        my $loop_starts_from_convex_point = 0;
-        my $cur_loop;
-        Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
-            my ($self, $cmd, $args, $info) = @_;
-            
-            if ($info->{extruding} && $info->{dist_XY} > 0) {
-                $cur_loop ||= [ [$self->X, $self->Y] ];
-                push @$cur_loop, [ @$info{qw(new_X new_Y)} ];
-            } else {
-                if ($cur_loop) {
-                    $loop_starts_from_convex_point = 1
-                        if Slic3r::Geometry::angle3points(@$cur_loop[0,-1,1]) >= PI;
-                    $cur_loop = undef;
-                }
-            }
-        });
-        ok !$loop_starts_from_convex_point, 'avoid starting from convex points';
-    }
-    
     {
         $config->set('perimeters', 1);
         $config->set('perimeter_speed', 77);
@@ -267,9 +245,9 @@ use Slic3r::Test;
 
 {
     my $config = Slic3r::Config->new_from_defaults;
-    $config->set('randomize_start', 1);
+    $config->set('seal_position', 'random');
     my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
-    ok Slic3r::Test::gcode($print), 'successful generation of G-code with randomize_start option';
+    ok Slic3r::Test::gcode($print), 'successful generation of G-code with seal_position = random';
 }
 
 __END__

+ 12 - 0
xs/src/MultiPoint.cpp

@@ -1,7 +1,13 @@
 #include "MultiPoint.hpp"
+#include "BoundingBox.hpp"
 
 namespace Slic3r {
 
+MultiPoint::operator Points() const
+{
+    return this->points;
+}
+
 void
 MultiPoint::scale(double factor)
 {
@@ -64,6 +70,12 @@ MultiPoint::find_point(const Point &point) const
     return -1;  // not found
 }
 
+void
+MultiPoint::bounding_box(BoundingBox* bb) const
+{
+    *bb = BoundingBox(this->points);
+}
+
 Points
 MultiPoint::_douglas_peucker(const Points &points, const double tolerance)
 {

Некоторые файлы не были показаны из-за большого количества измененных файлов