diff --git a/README.markdown b/README.markdown index f92a87869..30a0d3023 100644 --- a/README.markdown +++ b/README.markdown @@ -29,7 +29,9 @@ Slic3r current features are: * 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); +* generate rectilinear fill; +* set 0% - 100% infill density; +* set infill angle; * retraction; * skirt (with rounded corners); * use relative or absolute extrusion commands; diff --git a/lib/Slic3r.pm b/lib/Slic3r.pm index b1edfbca8..c52576acf 100644 --- a/lib/Slic3r.pm +++ b/lib/Slic3r.pm @@ -48,6 +48,7 @@ our $flow_width; our $perimeter_offsets = 3; our $solid_layers = 3; our $fill_density = 0.4; # 1 = 100% +our $fill_angle = 0; our $temperature = 195; # retraction options diff --git a/lib/Slic3r/Fill/Rectilinear.pm b/lib/Slic3r/Fill/Rectilinear.pm index ef419a0f8..795f74e12 100644 --- a/lib/Slic3r/Fill/Rectilinear.pm +++ b/lib/Slic3r/Fill/Rectilinear.pm @@ -20,7 +20,7 @@ sub make_fill { my ($print, $layer) = @_; printf "Filling layer %d:\n", $layer->id; - my $max_print_dimension = $print->max_length; + my $max_print_dimension = $print->max_length * sqrt(2); my $n = 1; foreach my $surface_collection (@{ $layer->fill_surfaces }) { @@ -30,18 +30,23 @@ sub make_fill { Slic3r::debugf " Processing surface %s:\n", $surface->id; my $polygon = $surface->mgp_polygon; - # alternate fill direction + # set infill angle my (@rotate, @shift); + $rotate[0] = Slic3r::Geometry::deg2rad($Slic3r::fill_angle); + $rotate[1] = [ $print->x_length / 2, $print->y_length / 2 ]; + $shift[X] = $max_print_dimension / 2; + $shift[Y] = $max_print_dimension / 2; + + # alternate fill direction if ($layer->id % 2) { - @rotate = ( PI/2, [ $print->x_length / 2, $print->y_length / 2 ] ); - $shift[X] = $print->y_length / 2 - $print->x_length / 2; - $shift[Y] = -$shift[X]; + $rotate[0] = Slic3r::Geometry::deg2rad($Slic3r::fill_angle) + PI/2; } # TODO: here we should implement an "infill in direction of bridges" option # rotate surface as needed - $polygon = $polygon->rotate(@rotate)->move(@shift) if @rotate; + @shift = @{ +(Slic3r::Geometry::rotate_points(@rotate, \@shift))[0] }; + $polygon = $polygon->rotate(@rotate)->move(@shift) if $rotate[0]; # force 100% density for external surfaces my $density = $surface->surface_type eq 'internal' ? $Slic3r::fill_density : 1; @@ -50,8 +55,8 @@ sub make_fill { my $distance_between_lines = $Slic3r::flow_width / $Slic3r::resolution / $density; my $number_of_lines = ceil($max_print_dimension / $distance_between_lines); - printf "distance = %f\n", $distance_between_lines; - printf "number_of_lines = %d\n", $number_of_lines; + #printf "distance = %f\n", $distance_between_lines; + #printf "number_of_lines = %d\n", $number_of_lines; # this arrayref will hold intersection points of the fill grid with surface segments my $points = [ map [], 0..$number_of_lines-1 ]; @@ -68,7 +73,7 @@ sub make_fill { $c <= $line_c[1]; $c += $distance_between_lines) { next if $c < $line_c[0] || $c > $line_c[1]; my $i = sprintf('%.0f', $c / $distance_between_lines) - 1; - printf "CURRENT \$i = %d, \$c = %f\n", $i, $c; + #printf "CURRENT \$i = %d, \$c = %f\n", $i, $c; # if the segment is parallel to our ray, there will be two intersection points if ($line_c[0] == $line_c[1]) { @@ -157,9 +162,9 @@ sub make_fill { } # paths must be rotated back - if (@rotate) { - # TODO: this skips 2-points paths! we shouldn't create a mgp polygon - @paths = map $self->_mgp_from_points_ref($_)->move(map -$_, @shift)->rotate(-$rotate[0], $rotate[1])->points, @paths; + if ($rotate[0]) { + @paths = map [ Slic3r::Geometry::rotate_points(-$rotate[0], $rotate[1], @$_) ], + map [ Slic3r::Geometry::move_points([map -$_, @shift], @$_) ], @paths; } push @path_collection, @paths; @@ -194,7 +199,7 @@ sub find_connectable_points { sub can_connect { my $self = shift; my ($polygon, $p1, $p2) = @_; - printf " Checking connectability of point %d\n", $p2->[1]; + #printf " Checking connectability of point %d\n", $p2->[1]; # there's room for optimization here diff --git a/lib/Slic3r/Geometry.pm b/lib/Slic3r/Geometry.pm index e0d2c0d22..c50eb7f7c 100644 --- a/lib/Slic3r/Geometry.pm +++ b/lib/Slic3r/Geometry.pm @@ -4,6 +4,7 @@ use warnings; use XXX; +use constant PI => 4 * atan2(1, 1); use constant A => 0; use constant B => 1; use constant X => 0; @@ -145,4 +146,25 @@ sub point_along_segment { return $point; } +sub deg2rad { + my ($degrees) = @_; + return PI() * $degrees / 180; +} + +sub rotate_points { + my ($radians, $center, @points) = @_; + $center ||= [0,0]; + return map { + [ + $center->[X] + cos($radians) * ($_->[X] - $center->[X]) - sin($radians) * ($_->[Y] - $center->[Y]), + $center->[Y] + cos($radians) * ($_->[Y] - $center->[Y]) + sin($radians) * ($_->[X] - $center->[X]), + ] + } @points; +} + +sub move_points { + my ($shift, @points) = @_; + return map [ $shift->[X] + $_->[X], $shift->[Y] + $_->[Y] ], @points; +} + 1; diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index b957d1177..2f2e3c286 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -156,6 +156,8 @@ sub export_gcode { my $self = shift; my ($file) = @_; + printf "Exporting GCODE file...\n"; + # open output gcode file open my $fh, ">", $file or die "Failed to open $file for writing\n"; diff --git a/slic3r.pl b/slic3r.pl index d7855d951..5a625e812 100755 --- a/slic3r.pl +++ b/slic3r.pl @@ -41,6 +41,7 @@ GetOptions( 'perimeters=i' => \$Slic3r::perimeter_offsets, 'solid-layers=i' => \$Slic3r::solid_layers, 'fill-density=f' => \$Slic3r::fill_density, + 'fill-angle=i' => \$Slic3r::fill_angle, 'temperature=i' => \$Slic3r::temperature, # retraction options @@ -159,6 +160,7 @@ Usage: slic3r.pl [ OPTIONS ] file.stl --solid-layers Number of solid layers to do for top/bottom surfaces (range: 1+, default: $Slic3r::solid_layers) --fill-density Infill density (range: 0-1, default: $Slic3r::fill_density) + --fill-angle Infill angle (range: 0-90, default: $Slic3r::fill_angle) --temperature Extrusion temperature (default: $Slic3r::temperature) Retraction options: