diff --git a/README.markdown b/README.markdown index 414cc1fb2..35a54647e 100644 --- a/README.markdown +++ b/README.markdown @@ -33,6 +33,7 @@ Slic3r is able to: * read binary and ASCII STL files; * generate multiple perimeters (skins); * generate rectilinear fill (100% solid for external surfaces or with customizable less density for inner surfaces); +* retraction; * use relative or absolute extrusion commands; * center print around bed center point; * use different speed for bottom layer; @@ -42,10 +43,10 @@ Roadmap includes the following goals: * output some statistics; * allow the user to customize initial and final GCODE commands; -* retraction; * option for filling multiple solid layers near external surfaces; * support material for internal perimeters; * ability to infill in the direction of bridges; +* extra perimeters on alternate layers; * skirt; * cool; * nice packaging for cross-platform deployment. diff --git a/lib/Slic3r.pm b/lib/Slic3r.pm index 1ae67b857..b876c2a56 100644 --- a/lib/Slic3r.pm +++ b/lib/Slic3r.pm @@ -24,15 +24,20 @@ use Slic3r::Surface; our $layer_height = 0.4; our $resolution = 0.1; our $perimeter_offsets = 3; -our $fill_density = 0.2; # 1 = 100% -our $flow_width = 0.4; +our $fill_density = 0.4; # 1 = 100% +our $filament_diameter = 3; # mm +our $filament_packing_density = 0.85; +our $flow_width = 0.50; our $temperature = 195; -our $flow_rate = 60; # mm/sec our $print_feed_rate = 60; # mm/sec our $travel_feed_rate = 80; # mm/sec our $bottom_layer_speed_ratio = 0.6; +our $retract_length = 2; # mm +our $retract_restart_extra = 0; # mm +our $retract_speed = 40; # mm/sec + our $use_relative_e_distances = 0; our $print_center = [100,100]; # object will be centered around this point diff --git a/lib/Slic3r/Fill/Rectilinear.pm b/lib/Slic3r/Fill/Rectilinear.pm index 0edd89f94..1acccbfb7 100644 --- a/lib/Slic3r/Fill/Rectilinear.pm +++ b/lib/Slic3r/Fill/Rectilinear.pm @@ -19,7 +19,7 @@ sub make_fill { # let's alternate fill direction my @axes = $layer->id % 2 == 0 ? (0,1) : (1,0); - foreach my $surface (@{ $layer->fill_surfaces }) { + SURFACE: foreach my $surface (@{ $layer->fill_surfaces }) { Slic3r::debugf " Processing surface %s:\n", $surface->id; my $polygon = $surface->mgp_polygon; @@ -30,6 +30,7 @@ sub make_fill { # force 100% density for external surfaces my $density = $surface->surface_type eq 'internal' ? $Slic3r::fill_density : 1; + next SURFACE unless $density > 0; my $distance_between_lines = $Slic3r::flow_width / $Slic3r::resolution / $density; my $number_of_lines = ($axes[0] == 0 ? $print->x_length : $print->y_length) / $distance_between_lines; @@ -96,7 +97,7 @@ sub make_fill { # loop through rows ROW: for (my $i = 0; $i < $number_of_lines; $i++) { - my $row = $points->[$i]; + my $row = $points->[$i] or next ROW; Slic3r::debugf "Processing row %d...\n", $i; if (!@$row) { Slic3r::debugf " no points\n"; diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index 4f503bdaf..565835662 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -1,6 +1,7 @@ package Slic3r::Print; use Moose; +use constant PI => 4 * atan2(1, 1); use constant X => 0; use constant Y => 1; @@ -75,10 +76,10 @@ sub export_gcode { # calculate speed for gcode commands my $travel_feed_rate = $Slic3r::travel_feed_rate * 60; # mm/min my $print_feed_rate = $Slic3r::print_feed_rate * 60; # mm/min - my $extrusion_speed_ratio = ($Slic3r::flow_rate / $Slic3r::print_feed_rate); + my $retract_speed = $Slic3r::retract_speed * 60; # mm/min # calculate number of decimals - my $dec = length((1 / $Slic3r::resolution) - 1); + my $dec = length((1 / $Slic3r::resolution) - 1) + 1; # calculate X,Y shift to center print around specified origin my @shift = ( @@ -103,17 +104,33 @@ sub export_gcode { } # make up a subroutine to generate G1 commands + my $extrusion_distance = 0; my $G1 = sub { - my ($point, $z, $extrusion_distance, $comment) = @_; - printf $fh "G1 X%.${dec}f Y%.${dec}f Z%.${dec}f", - ($point->x * $Slic3r::resolution) + $shift[X], - ($point->y * $Slic3r::resolution) + $shift[Y], #** - $z; - my $speed_multiplier = $z == 0 ? $Slic3r::bottom_layer_speed_ratio : 1; - if ($extrusion_distance) { - printf $fh " F%.${dec}f E%.${dec}f", - ($print_feed_rate * $speed_multiplier), - ($extrusion_distance * $extrusion_speed_ratio * $Slic3r::resolution); + my ($point, $z, $e, $comment) = @_; + printf $fh "G1"; + + if ($point) { + printf $fh " X%.${dec}f Y%.${dec}f", + ($point->x * $Slic3r::resolution) + $shift[X], + ($point->y * $Slic3r::resolution) + $shift[Y]; #** + } + if ($z) { + printf $fh " Z%.${dec}f", $z; + } + + # apply the speed reduction for print moves on bottom layer + my $speed_multiplier = defined $z && $z == 0 && $point + ? $Slic3r::bottom_layer_speed_ratio + : 1; + + if ($e) { + $extrusion_distance = 0 if $Slic3r::use_relative_e_distances; + $extrusion_distance += $e; + printf $fh " F%.${dec}f E%.5f", + $e < 0 + ? $retract_speed + : ($print_feed_rate * $speed_multiplier), + $extrusion_distance; } else { printf $fh " F%.${dec}f", ($travel_feed_rate * $speed_multiplier); } @@ -122,26 +139,41 @@ sub export_gcode { }; my $z; + my $retracted = 0; my $Extrude = sub { my ($path, $description) = @_; # reset extrusion distance counter - my $extrusion_distance = 0; if (!$Slic3r::use_relative_e_distances) { + $extrusion_distance = 0; print $fh "G92 E0 ; reset extrusion distance\n"; } - # go to first point (without extruding) - $G1->($path->lines->[0]->a, $z, 0, "move to first $description point"); + # go to first point while compensating retraction + $G1->($path->lines->[0]->a, $z, + $retracted + ? ($Slic3r::retract_length + $Slic3r::retract_restart_extra) + : 0, + "move to first $description point"); # extrude while going to next points foreach my $line (@{ $path->lines }) { - $extrusion_distance = 0 if $Slic3r::use_relative_e_distances; - $extrusion_distance += $line->a->distance_to($line->b); - $G1->($line->b, $z, $extrusion_distance, $description); + # calculate how much filament to drive into the extruder + # to get the desired amount of extruded plastic + my $e = $line->a->distance_to($line->b) * $Slic3r::resolution + * $Slic3r::flow_width + * $Slic3r::layer_height + / (($Slic3r::filament_diameter ** 2) * PI) + / $Slic3r::filament_packing_density; + + $G1->($line->b, $z, $e, $description); } - # TODO: retraction + # retract + if ($Slic3r::retract_length > 0) { + $G1->(undef, undef, -$Slic3r::retract_length, "retract"); + $retracted = 1; + } }; # write gcode commands layer by layer diff --git a/slic3r.pl b/slic3r.pl index c89878805..ecbb39028 100644 --- a/slic3r.pl +++ b/slic3r.pl @@ -10,6 +10,7 @@ BEGIN { use Getopt::Long; use Slic3r; +use Time::HiRes qw(gettimeofday tv_interval); use XXX; my %opt; @@ -23,15 +24,16 @@ GetOptions( 'resolution=f' => \$Slic3r::resolution, 'perimeters=i' => \$Slic3r::perimeter_offsets, 'fill-density=f' => \$Slic3r::fill_density, + 'filament-diameter=f' => \$Slic3r::filament_diameter, 'flow-width=f' => \$Slic3r::flow_width, 'temperature=i' => \$Slic3r::temperature, - 'flow-rate=i' => \$Slic3r::flow_rate, 'print-feed-rate=i' => \$Slic3r::print_feed_rate, 'travel-feed-rate=i' => \$Slic3r::travel_feed_rate, 'bottom-layer-speed-ratio=f' => \$Slic3r::bottom_layer_speed_ratio, 'use-relative-e-distances' => \$Slic3r::use_relative_e_distances, 'print-center=s' => \$Slic3r::print_center, - '', + 'retract-length=f' => \$Slic3r::retract_length, + 'retract-restart-extra=f' => \$Slic3r::retract_restart_extra, ); # validate configuration @@ -42,6 +44,10 @@ GetOptions( die "--layer-height must be a multiple of print resolution\n" if $Slic3r::layer_height / $Slic3r::resolution % 1 != 0; + # --filament-diameter + die "Invalid value for --filament-diameter\n" + if $Slic3r::filament_diameter < 1; + # --flow-width die "Invalid value for --flow-width\n" if $Slic3r::flow_width < 0; @@ -72,6 +78,7 @@ if ($action eq 'skein') { die "Input file must have .stl extension\n" if $input_file !~ /\.stl$/i; + my $t0 = [gettimeofday]; my $print = $stl_parser->parse_file($input_file); $print->extrude_perimeters; $print->extrude_fills; @@ -79,6 +86,10 @@ if ($action eq 'skein') { my $output_file = $input_file; $output_file =~ s/\.stl$/.gcode/i; $print->export_gcode($opt{output} || $output_file); + + my $processing_time = tv_interval($t0); + printf "Done. Process took %d minutes and %.3f seconds\n", + int($processing_time/60), $processing_time - int($processing_time/60); } sub usage { @@ -93,14 +104,22 @@ Usage: slic3r.pl [ OPTIONS ] file.stl --perimeters Number of perimeters/horizontal skins (range: 1+, default: $Slic3r::perimeter_offsets) --fill-density Infill density (range: 0-1, default: $Slic3r::fill_density) + --filament-diameter Diameter of your raw filament (default: $Slic3r::filament_diameter) + --filament-packing-density + Ratio of the extruded volume over volume pushed into + the extruder (default: $Slic3r::filament_packing_density) --flow-width Width of extruded flow in mm (default: $Slic3r::flow_width) - --flow-rate Speed of extrusion in mm/sec; should be equal to - --print-feed-rate (default: $Slic3r::flow_rate) --print-feed-rate Speed of print moves in mm/sec (default: $Slic3r::print_feed_rate) --travel-feed-rate Speed of non-print moves in mm/sec (default: $Slic3r::travel_feed_rate) --bottom-layer-speed-ratio Factor to increase/decrease speeds on bottom layer by (default: $Slic3r::bottom_layer_speed_ratio) + --retract-length Length of retraction in mm when pausing extrusion + (default: $Slic3r::retract_length) + --retract-speed Speed for retraction in mm/sec (default: $Slic3r::retract_speed) + --retract-restart-extra + Additional amount of filament in mm to push after compensating + retraction (default: $Slic3r::retract_restart_extra) --use-relative-e-distances Use relative distances for extrusion in GCODE output --print-center Coordinates of the point to center the print around