PrusaSlicer-NonPlainar/lib/Slic3r/Fill/Honeycomb.pm

94 lines
3.8 KiB
Perl
Raw Normal View History

2012-04-16 09:55:14 +00:00
package Slic3r::Fill::Honeycomb;
use Moo;
extends 'Slic3r::Fill::Base';
has 'cache' => (is => 'rw', default => sub {{}});
2012-04-16 09:55:14 +00:00
use Slic3r::Geometry qw(PI X Y MIN MAX scale);
2012-04-16 09:55:14 +00:00
use Slic3r::Geometry::Clipper qw(intersection_ex);
sub angles () { [0, PI/3, PI/3*2] }
sub fill_surface {
my $self = shift;
my ($surface, %params) = @_;
my $rotate_vector = $self->infill_direction($surface);
# cache hexagons math
my $cache_id = sprintf "d%s_s%s", $params{density}, $params{flow_spacing};
my $m;
if (!($m = $self->cache->{$cache_id})) {
$m = $self->cache->{$cache_id} = {};
my $min_spacing = scale $params{flow_spacing};
$m->{distance} = $min_spacing / $params{density};
$m->{hex_side} = $m->{distance} / (sqrt(3)/2);
$m->{hex_width} = $m->{distance} * 2; # $m->{hex_width} == $m->{hex_side} * sqrt(3);
my $hex_height = $m->{hex_side} * 2;
$m->{pattern_height} = $hex_height + $m->{hex_side};
$m->{y_short} = $m->{distance} * sqrt(3)/3;
$m->{x_offset} = $min_spacing / 2;
$m->{y_offset} = $m->{x_offset} * sqrt(3)/3;
$m->{hex_center} = Slic3r::Point->new($m->{hex_width}/2, $m->{hex_side});
}
2012-04-16 09:55:14 +00:00
my @polygons = ();
{
2012-04-16 09:55:14 +00:00
# adjust actual bounding box to the nearest multiple of our hex pattern
# and align it so that it matches across layers
my $bounding_box = $surface->expolygon->bounding_box;
2012-04-16 09:55:14 +00:00
{
# rotate bounding box according to infill direction
my $bb_polygon = $bounding_box->polygon;
$bb_polygon->rotate($rotate_vector->[0][0], $m->{hex_center});
$bounding_box = $bb_polygon->bounding_box;
# extend bounding box so that our pattern will be aligned with other layers
# $bounding_box->[X1] and [Y1] represent the displacement between new bounding box offset and old one
$bounding_box->extents->[X][MIN] -= $bounding_box->x_min % $m->{hex_width};
$bounding_box->extents->[Y][MIN] -= $bounding_box->y_min % $m->{pattern_height};
2012-04-16 09:55:14 +00:00
}
my $x = $bounding_box->x_min;
while ($x <= $bounding_box->x_max) {
2012-04-16 09:55:14 +00:00
my $p = [];
my @x = ($x + $m->{x_offset}, $x + $m->{distance} - $m->{x_offset});
2012-04-16 09:55:14 +00:00
for (1..2) {
@$p = reverse @$p; # turn first half upside down
my @p = ();
for (my $y = $bounding_box->y_min; $y <= $bounding_box->y_max; $y += $m->{y_short} + $m->{hex_side} + $m->{y_short} + $m->{hex_side}) {
2012-04-16 09:55:14 +00:00
push @$p,
[ $x[1], $y + $m->{y_offset} ],
[ $x[0], $y + $m->{y_short} - $m->{y_offset} ],
[ $x[0], $y + $m->{y_short} + $m->{hex_side} + $m->{y_offset} ],
[ $x[1], $y + $m->{y_short} + $m->{hex_side} + $m->{y_short} - $m->{y_offset} ],
[ $x[1], $y + $m->{y_short} + $m->{hex_side} + $m->{y_short} + $m->{hex_side} + $m->{y_offset} ];
2012-04-16 09:55:14 +00:00
}
@x = map $_ + $m->{distance}, reverse @x; # draw symmetrical pattern
$x += $m->{distance};
2012-04-16 09:55:14 +00:00
}
push @polygons, Slic3r::Polygon->new($p);
}
$_->rotate(-$rotate_vector->[0][0], $m->{hex_center}) for @polygons;
2012-04-16 09:55:14 +00:00
}
2013-03-26 12:04:57 +00:00
# consider polygons as polylines without re-appending the initial point:
# this cuts the last segment on purpose, so that the jump to the next
# path is more straight
2013-03-26 12:04:57 +00:00
my @paths = map Slic3r::Polyline->new($_),
@{ Boost::Geometry::Utils::polygon_multi_linestring_intersection(
$surface->expolygon,
\@polygons,
2013-03-26 12:04:57 +00:00
) };
2012-04-16 09:55:14 +00:00
return { flow_spacing => $params{flow_spacing} },
Slic3r::Polyline::Collection->new(polylines => \@paths)->chained_path;
2012-04-16 09:55:14 +00:00
}
1;