Align rectilinear and line infill across layers (new implementation). #712
This commit is contained in:
parent
c723c07f8c
commit
430c825918
@ -161,11 +161,6 @@ sub bounding_box_polygon {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub bounding_box_center {
|
|
||||||
my $self = shift;
|
|
||||||
return Slic3r::Geometry::bounding_box_center($self->contour);
|
|
||||||
}
|
|
||||||
|
|
||||||
sub clip_line {
|
sub clip_line {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my ($line) = @_; # line must be a Slic3r::Line object
|
my ($line) = @_; # line must be a Slic3r::Line object
|
||||||
|
@ -39,10 +39,9 @@ sub filler {
|
|||||||
return $FillTypes{$filler}->new;
|
return $FillTypes{$filler}->new;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$self->fillers->{$filler}) {
|
$self->fillers->{$filler} ||= $FillTypes{$filler}->new(
|
||||||
my $f = $self->fillers->{$filler} = $FillTypes{$filler}->new;
|
bounding_box => [ $self->print->bounding_box ],
|
||||||
$f->bounding_box([ $self->print->bounding_box ]) if $f->can('bounding_box');
|
);
|
||||||
}
|
|
||||||
return $self->fillers->{$filler};
|
return $self->fillers->{$filler};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ use Slic3r::Geometry qw(PI);
|
|||||||
|
|
||||||
has 'layer_id' => (is => 'rw');
|
has 'layer_id' => (is => 'rw');
|
||||||
has 'angle' => (is => 'rw', default => sub { $Slic3r::Config->fill_angle });
|
has 'angle' => (is => 'rw', default => sub { $Slic3r::Config->fill_angle });
|
||||||
|
has 'bounding_box' => (is => 'ro', required => 1);
|
||||||
|
|
||||||
sub angles () { [0, PI/2] }
|
sub angles () { [0, PI/2] }
|
||||||
|
|
||||||
@ -15,7 +16,7 @@ sub infill_direction {
|
|||||||
# set infill angle
|
# set infill angle
|
||||||
my (@rotate, @shift);
|
my (@rotate, @shift);
|
||||||
$rotate[0] = Slic3r::Geometry::deg2rad($self->angle);
|
$rotate[0] = Slic3r::Geometry::deg2rad($self->angle);
|
||||||
$rotate[1] = $surface->expolygon->bounding_box_center;
|
$rotate[1] = Slic3r::Geometry::bounding_box_center($self->bounding_box);
|
||||||
@shift = @{$rotate[1]};
|
@shift = @{$rotate[1]};
|
||||||
|
|
||||||
if (defined $self->layer_id) {
|
if (defined $self->layer_id) {
|
||||||
@ -41,11 +42,9 @@ sub rotate_points {
|
|||||||
my @rotate = @{$rotate_vector->[0]};
|
my @rotate = @{$rotate_vector->[0]};
|
||||||
my @shift = @{$rotate_vector->[1]};
|
my @shift = @{$rotate_vector->[1]};
|
||||||
|
|
||||||
# rotate points as needed
|
# rotate points
|
||||||
if ($rotate[0]) {
|
$expolygon->rotate(@rotate);
|
||||||
$expolygon->rotate(@rotate);
|
$expolygon->translate(@shift);
|
||||||
$expolygon->translate(@shift);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub rotate_points_back {
|
sub rotate_points_back {
|
||||||
@ -54,10 +53,8 @@ sub rotate_points_back {
|
|||||||
my @rotate = @{$rotate_vector->[0]};
|
my @rotate = @{$rotate_vector->[0]};
|
||||||
my @shift = @{$rotate_vector->[1]};
|
my @shift = @{$rotate_vector->[1]};
|
||||||
|
|
||||||
if ($rotate[0]) {
|
@$paths = map [ Slic3r::Geometry::rotate_points(-$rotate[0], $rotate[1], @$_) ],
|
||||||
@$paths = map [ Slic3r::Geometry::rotate_points(-$rotate[0], $rotate[1], @$_) ],
|
map [ Slic3r::Geometry::move_points([map -$_, @shift], @$_) ], @$paths;
|
||||||
map [ Slic3r::Geometry::move_points([map -$_, @shift], @$_) ], @$paths;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub adjust_solid_spacing {
|
sub adjust_solid_spacing {
|
||||||
|
@ -3,7 +3,6 @@ use Moo;
|
|||||||
|
|
||||||
extends 'Slic3r::Fill::Base';
|
extends 'Slic3r::Fill::Base';
|
||||||
|
|
||||||
has 'bounding_box' => (is => 'rw');
|
|
||||||
has 'cache' => (is => 'rw', default => sub {{}});
|
has 'cache' => (is => 'rw', default => sub {{}});
|
||||||
|
|
||||||
use Slic3r::Geometry qw(PI X1 Y1 X2 Y2 X Y scale);
|
use Slic3r::Geometry qw(PI X1 Y1 X2 Y2 X Y scale);
|
||||||
@ -25,7 +24,7 @@ sub fill_surface {
|
|||||||
|
|
||||||
my $cache_id = sprintf "d%s_s%s_a%s",
|
my $cache_id = sprintf "d%s_s%s_a%s",
|
||||||
$params{density}, $params{flow_spacing}, $rotate_vector->[0][0];
|
$params{density}, $params{flow_spacing}, $rotate_vector->[0][0];
|
||||||
if (!$self->cache->{$cache_id} || !defined $self->bounding_box) {
|
if (!$self->cache->{$cache_id}) {
|
||||||
|
|
||||||
# hexagons math
|
# hexagons math
|
||||||
my $hex_side = $distance / (sqrt(3)/2);
|
my $hex_side = $distance / (sqrt(3)/2);
|
||||||
@ -39,7 +38,7 @@ sub fill_surface {
|
|||||||
|
|
||||||
# adjust actual bounding box to the nearest multiple of our hex pattern
|
# adjust actual bounding box to the nearest multiple of our hex pattern
|
||||||
# and align it so that it matches across layers
|
# and align it so that it matches across layers
|
||||||
my $bounding_box = [ $self->bounding_box ? @{$self->bounding_box} : $expolygon->bounding_box ];
|
my $bounding_box = [ @{$self->bounding_box} ]; # clone
|
||||||
$bounding_box->[$_] = 0 for X1, Y1;
|
$bounding_box->[$_] = 0 for X1, Y1;
|
||||||
{
|
{
|
||||||
my $bb_polygon = Slic3r::Polygon->new_from_bounding_box($bounding_box);
|
my $bb_polygon = Slic3r::Polygon->new_from_bounding_box($bounding_box);
|
||||||
|
@ -3,6 +3,8 @@ use Moo;
|
|||||||
|
|
||||||
extends 'Slic3r::Fill::Base';
|
extends 'Slic3r::Fill::Base';
|
||||||
|
|
||||||
|
has 'cache' => (is => 'rw', default => sub {{}});
|
||||||
|
|
||||||
use Slic3r::Geometry qw(X1 Y1 X2 Y2 A B X Y scale unscale scaled_epsilon);
|
use Slic3r::Geometry qw(X1 Y1 X2 Y2 A B X Y scale unscale scaled_epsilon);
|
||||||
|
|
||||||
sub fill_surface {
|
sub fill_surface {
|
||||||
@ -16,39 +18,55 @@ sub fill_surface {
|
|||||||
|
|
||||||
my ($expolygon_off) = $expolygon->offset_ex(scale $params{flow_spacing}/2);
|
my ($expolygon_off) = $expolygon->offset_ex(scale $params{flow_spacing}/2);
|
||||||
return {} if !$expolygon_off; # skip some very small polygons (which shouldn't arrive here)
|
return {} if !$expolygon_off; # skip some very small polygons (which shouldn't arrive here)
|
||||||
my $bounding_box = [ $expolygon->bounding_box ];
|
|
||||||
|
|
||||||
|
my $flow_spacing = $params{flow_spacing};
|
||||||
my $min_spacing = scale $params{flow_spacing};
|
my $min_spacing = scale $params{flow_spacing};
|
||||||
my $distance_between_lines = $min_spacing / $params{density};
|
my $distance_between_lines = $min_spacing / $params{density};
|
||||||
my $line_oscillation = $distance_between_lines - $min_spacing;
|
my $line_oscillation = $distance_between_lines - $min_spacing;
|
||||||
|
|
||||||
my $flow_spacing = $params{flow_spacing};
|
|
||||||
if ($params{density} == 1 && !$params{dont_adjust}) {
|
|
||||||
$distance_between_lines = $self->adjust_solid_spacing(
|
|
||||||
width => $bounding_box->[X2] - $bounding_box->[X1],
|
|
||||||
distance => $distance_between_lines,
|
|
||||||
);
|
|
||||||
$flow_spacing = unscale $distance_between_lines;
|
|
||||||
}
|
|
||||||
|
|
||||||
my $x = $bounding_box->[X1];
|
|
||||||
my $is_line_pattern = $self->isa('Slic3r::Fill::Line');
|
my $is_line_pattern = $self->isa('Slic3r::Fill::Line');
|
||||||
my @vertical_lines = ();
|
|
||||||
for (my $i = 0; $x <= $bounding_box->[X2] + scaled_epsilon; $i++) {
|
my $cache_id = sprintf "d%s_s%s_a%s",
|
||||||
my $vertical_line = Slic3r::Line->new([$x, $bounding_box->[Y2]], [$x, $bounding_box->[Y1]]);
|
$params{density}, $params{flow_spacing}, $rotate_vector->[0][0];
|
||||||
if ($is_line_pattern && $i % 2) {
|
|
||||||
$vertical_line->[A][X] += $line_oscillation;
|
if (!$self->cache->{$cache_id}) {
|
||||||
$vertical_line->[B][X] -= $line_oscillation;
|
# compute bounding box
|
||||||
|
my $bounding_box = $self->bounding_box;
|
||||||
|
{
|
||||||
|
my $bb_expolygon = Slic3r::ExPolygon->new(Slic3r::Polygon->new_from_bounding_box($bounding_box));
|
||||||
|
$self->rotate_points($bb_expolygon, $rotate_vector);
|
||||||
|
$bounding_box = [ $bb_expolygon->bounding_box ];
|
||||||
}
|
}
|
||||||
push @vertical_lines, $vertical_line;
|
|
||||||
$x += $distance_between_lines;
|
# define flow spacing according to requested density
|
||||||
|
if ($params{density} == 1 && !$params{dont_adjust}) {
|
||||||
|
$distance_between_lines = $self->adjust_solid_spacing(
|
||||||
|
width => $bounding_box->[X2] - $bounding_box->[X1],
|
||||||
|
distance => $distance_between_lines,
|
||||||
|
);
|
||||||
|
$flow_spacing = unscale $distance_between_lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
# generate the basic pattern
|
||||||
|
my $x = $bounding_box->[X1];
|
||||||
|
my @vertical_lines = ();
|
||||||
|
for (my $i = 0; $x <= $bounding_box->[X2] + scaled_epsilon; $i++) {
|
||||||
|
my $vertical_line = Slic3r::Line->new([$x, $bounding_box->[Y2]], [$x, $bounding_box->[Y1]]);
|
||||||
|
if ($is_line_pattern && $i % 2) {
|
||||||
|
$vertical_line->[A][X] += $line_oscillation;
|
||||||
|
$vertical_line->[B][X] -= $line_oscillation;
|
||||||
|
}
|
||||||
|
push @vertical_lines, $vertical_line;
|
||||||
|
$x += $distance_between_lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
$self->cache->{$cache_id} = [@vertical_lines];
|
||||||
}
|
}
|
||||||
|
|
||||||
# clip paths against a slightly offsetted expolygon, so that the first and last paths
|
# clip paths against a slightly offsetted expolygon, so that the first and last paths
|
||||||
# are kept even if the expolygon has vertical sides
|
# are kept even if the expolygon has vertical sides
|
||||||
my @paths = @{ Boost::Geometry::Utils::polygon_multi_linestring_intersection(
|
my @paths = @{ Boost::Geometry::Utils::polygon_multi_linestring_intersection(
|
||||||
+($expolygon->offset_ex(scaled_epsilon))[0], # TODO: we should use all the resulting expolygons and clip the linestrings to a multipolygon object
|
+($expolygon->offset_ex(scaled_epsilon))[0], # TODO: we should use all the resulting expolygons and clip the linestrings to a multipolygon object
|
||||||
[ @vertical_lines ],
|
[ @{ $self->cache->{$cache_id} } ],
|
||||||
) };
|
) };
|
||||||
|
|
||||||
# connect lines
|
# connect lines
|
||||||
|
@ -679,10 +679,10 @@ sub bounding_box {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub bounding_box_center {
|
sub bounding_box_center {
|
||||||
my @bounding_box = bounding_box(@_);
|
my ($bounding_box) = @_;
|
||||||
return Slic3r::Point->new(
|
return Slic3r::Point->new(
|
||||||
($bounding_box[X2] + $bounding_box[X1]) / 2,
|
($bounding_box->[X2] + $bounding_box->[X1]) / 2,
|
||||||
($bounding_box[Y2] + $bounding_box[Y1]) / 2,
|
($bounding_box->[Y2] + $bounding_box->[Y1]) / 2,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -894,6 +894,7 @@ sub generate_support_material {
|
|||||||
|
|
||||||
# generate paths for the pattern that we're going to use
|
# generate paths for the pattern that we're going to use
|
||||||
Slic3r::debugf "Generating patterns\n";
|
Slic3r::debugf "Generating patterns\n";
|
||||||
|
my $fill = Slic3r::Fill->new(print => $self->print);
|
||||||
my $support_patterns = [];
|
my $support_patterns = [];
|
||||||
my $support_interface_patterns = [];
|
my $support_interface_patterns = [];
|
||||||
{
|
{
|
||||||
@ -908,10 +909,7 @@ sub generate_support_material {
|
|||||||
push @angles, $angles[0] + 90;
|
push @angles, $angles[0] + 90;
|
||||||
}
|
}
|
||||||
|
|
||||||
my $filler = Slic3r::Fill->filler($pattern);
|
my $filler = $fill->filler($pattern);
|
||||||
$filler->bounding_box([ Slic3r::Geometry::bounding_box([ map @$_, map @$_, @areas ]) ])
|
|
||||||
if $filler->can('bounding_box');
|
|
||||||
|
|
||||||
my $make_pattern = sub {
|
my $make_pattern = sub {
|
||||||
my ($expolygon, $density) = @_;
|
my ($expolygon, $density) = @_;
|
||||||
|
|
||||||
@ -996,7 +994,7 @@ sub generate_support_material {
|
|||||||
|
|
||||||
# make a solid base on bottom layer
|
# make a solid base on bottom layer
|
||||||
if ($layer_id == 0) {
|
if ($layer_id == 0) {
|
||||||
my $filler = Slic3r::Fill->filler('rectilinear');
|
my $filler = $fill->filler('rectilinear');
|
||||||
$filler->angle($Slic3r::Config->support_material_angle + 90);
|
$filler->angle($Slic3r::Config->support_material_angle + 90);
|
||||||
foreach my $expolygon (@$islands) {
|
foreach my $expolygon (@$islands) {
|
||||||
my @paths = $filler->fill_surface(
|
my @paths = $filler->fill_surface(
|
||||||
|
Loading…
Reference in New Issue
Block a user