diff --git a/lib/Slic3r/ExPolygon.pm b/lib/Slic3r/ExPolygon.pm index 70e3f4f97b..5d87f720f9 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 scale epsilon); +use Slic3r::Geometry qw(X Y A B point_in_polygon same_line line_length scale epsilon); 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 && abs($line->length - Slic3r::Geometry::line_length($clip->[0])) < scale epsilon; + 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/GCode.pm b/lib/Slic3r/GCode.pm index 273753d412..842cf2b0fc 100644 --- a/lib/Slic3r/GCode.pm +++ b/lib/Slic3r/GCode.pm @@ -11,8 +11,10 @@ has 'shift_y' => (is => 'rw', default => sub {0} ); has 'z' => (is => 'rw', default => sub {0} ); has 'speed' => (is => 'rw'); -has 'motionplanner' => (is => 'rw'); -has 'straight_once' => (is => 'rw'); +has 'external_mp' => (is => 'rw'); +has 'layer_mp' => (is => 'rw'); +has 'new_object' => (is => 'rw', default => sub {0}); +has 'straight_once' => (is => 'rw', default => sub {1}); has 'extruder_idx' => (is => 'rw'); has 'extrusion_distance' => (is => 'rw', default => sub {0} ); has 'elapsed_time' => (is => 'rw', default => sub {0} ); # seconds @@ -76,7 +78,7 @@ sub change_layer { $self->layer($layer); if ($Slic3r::Config->avoid_crossing_perimeters) { - $self->motionplanner(Slic3r::GCode::MotionPlanner->new( + $self->layer_mp(Slic3r::GCode::MotionPlanner->new( islands => union_ex([ map @{$_->expolygon}, @{$layer->slices} ], undef, 1), )); } @@ -216,13 +218,32 @@ sub travel_to { my ($point, $comment) = @_; return "" if points_coincide($self->last_pos, $point); + + my $gcode = ""; if ($Slic3r::Config->avoid_crossing_perimeters && $self->last_pos->distance_to($point) > scale 5 && !$self->straight_once) { - return join '', map $self->G0($_->b, undef, 0, $comment || ""), - $self->motionplanner->shortest_path($self->last_pos, $point)->lines; + my $plan = sub { + my $mp = shift; + return join '', + map $self->G0($_->b, undef, 0, $comment || ""), + $mp->shortest_path($self->last_pos, $point)->lines; + }; + + if ($self->new_object) { + my @shift = ($self->shift_x, $self->shift_y); + $self->set_shift(0,0); + $point->translate(map scale $_, @shift); + $gcode .= $plan->($self->external_mp); + $self->new_object(0); + $self->set_shift(@shift); + } else { + $gcode .= $plan->($self->layer_mp); + } } else { $self->straight_once(0); - return $self->G0($point, undef, 0, $comment || ""); + $gcode .= $self->G0($point, undef, 0, $comment || ""); } + + return $gcode; } sub retract { diff --git a/lib/Slic3r/GCode/MotionPlanner.pm b/lib/Slic3r/GCode/MotionPlanner.pm index b95a38ec61..ef55f16cc9 100644 --- a/lib/Slic3r/GCode/MotionPlanner.pm +++ b/lib/Slic3r/GCode/MotionPlanner.pm @@ -45,7 +45,7 @@ sub BUILD { for my $i (0 .. $#points) { for my $j (($i+1) .. $#points) { my $line = Slic3r::Line->new($points[$i], $points[$j]); - if ($expolygon->encloses_line($line, scale Slic3r::Geometry::epsilon)) { + if ($expolygon->encloses_line($line, $tolerance)) { my $dist = $line->length * ($crosses_perimeter ? CROSSING_FACTOR : 1); $edges->{$points[$i]}{$points[$j]} = $dist; $edges->{$points[$j]}{$points[$i]} = $dist; diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index df1fc4c0a1..3f2b1769f8 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -614,7 +614,6 @@ sub write_gcode { ); # initialize a motion planner for object-to-object travel moves - my $external_motionplanner; if ($Slic3r::Config->avoid_crossing_perimeters) { my $distance_from_objects = 1; # compute the offsetted convex hull for each object and repeat it for each copy. @@ -622,15 +621,15 @@ sub write_gcode { foreach my $obj_idx (0 .. $#{$self->objects}) { my @island = Slic3r::ExPolygon->new(convex_hull([ map @{$_->expolygon->contour}, map @{$_->slices}, @{$self->objects->[$obj_idx]->layers}, - ]))->translate(map -$_, @shift)->offset_ex(scale $distance_from_objects); + ]))->translate(scale $shift[X], scale $shift[Y])->offset_ex(scale $distance_from_objects, 1, JT_SQUARE); foreach my $copy (@{$self->copies->[$obj_idx]}) { push @islands, map $_->clone->translate(@$copy), @island; } } - $external_motionplanner = Slic3r::GCode::MotionPlanner->new( + $gcodegen->external_mp(Slic3r::GCode::MotionPlanner->new( islands => union_ex([ map @$_, @islands ]), no_internal => 1, - ); + )); } # prepare the logic to print one layer @@ -663,6 +662,7 @@ sub write_gcode { $gcode .= $gcodegen->extrude_loop($_, 'skirt') for @{$self->skirt}; } $skirt_done++; + $gcodegen->straight_once(1); } # extrude brim @@ -670,27 +670,18 @@ sub write_gcode { $gcodegen->set_shift(@shift); $gcode .= $gcodegen->extrude_loop($_, 'brim') for @{$self->brim}; $brim_done = 1; + $gcodegen->straight_once(1); } for my $obj_copy (@$object_copies) { my ($obj_idx, $copy) = @$obj_copy; + $gcodegen->new_object(1) if $last_obj_copy && $last_obj_copy ne "${obj_idx}_${copy}"; my $layer = $self->objects->[$obj_idx]->layers->[$layer_id]; # retract explicitely because changing the shift_[xy] properties below # won't always trigger the automatic retraction $gcode .= $gcodegen->retract; - # travel to the first perimeter point using the external motion planner - if ($external_motionplanner && @{ $layer->perimeters } && !$gcodegen->straight_once && $last_obj_copy ne "${obj_idx}_${copy}") { - $gcodegen->set_shift(@shift); - my $layer_mp = $gcodegen->motionplanner; - $gcodegen->motionplanner($external_motionplanner); - my $first_perimeter = $layer->perimeters->[0]->unpack; - my $target = $first_perimeter->polygon->[0]->clone->translate(@$copy); - $gcode .= $gcodegen->travel_to($target, "move to first perimeter point"); - $gcodegen->motionplanner($layer_mp); - } - $gcodegen->set_shift( $shift[X] + unscale $copy->[X], $shift[Y] + unscale $copy->[Y], @@ -773,8 +764,10 @@ sub write_gcode { # this happens before Z goes down to layer 0 again, so that # no collision happens hopefully. if ($finished_objects > 0) { - $gcodegen->shift_x($shift[X] + unscale $copy->[X]); - $gcodegen->shift_y($shift[Y] + unscale $copy->[Y]); + $gcodegen->set_shift( + $shift[X] + unscale $copy->[X], + $shift[Y] + unscale $copy->[Y], + ); print $fh $gcodegen->retract; print $fh $gcodegen->G0(Slic3r::Point->new(0,0), undef, 0, 'move to origin position for next object'); }