diff --git a/lib/Slic3r/Fill/Honeycomb.pm b/lib/Slic3r/Fill/Honeycomb.pm index e75918d8b..75e2687d6 100644 --- a/lib/Slic3r/Fill/Honeycomb.pm +++ b/lib/Slic3r/Fill/Honeycomb.pm @@ -14,69 +14,67 @@ sub fill_surface { my $self = shift; my ($surface, %params) = @_; - # rotate polygons so that we can work with vertical lines here - my $expolygon = $surface->expolygon->clone; my $rotate_vector = $self->infill_direction($surface); - # infill math - my $min_spacing = scale $params{flow_spacing}; - my $distance = $min_spacing / $params{density}; + # 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}); + } - my $cache_id = sprintf "d%s_s%s_a%s", - $params{density}, $params{flow_spacing}, $rotate_vector->[0][0]; - if (!$self->cache->{$cache_id}) { - - # hexagons math - my $hex_side = $distance / (sqrt(3)/2); - my $hex_width = $distance * 2; # $hex_width == $hex_side * sqrt(3); - my $hex_height = $hex_side * 2; - my $pattern_height = $hex_height + $hex_side; - my $y_short = $distance * sqrt(3)/3; - my $x_offset = $min_spacing / 2; - my $y_offset = $x_offset * sqrt(3)/3; - my $hex_center = Slic3r::Point->new($hex_width/2, $hex_side); - + my @polygons = (); + { # adjust actual bounding box to the nearest multiple of our hex pattern # and align it so that it matches across layers - my $bounding_box = $self->bounding_box->clone; - $bounding_box->extents->[$_][MIN] = 0 for X, Y; + my $bounding_box = $surface->expolygon->bounding_box; { + # rotate bounding box according to infill direction my $bb_polygon = $bounding_box->polygon; - $bb_polygon->scale(sqrt 2); - $bb_polygon->rotate($rotate_vector->[0][0], $hex_center); + $bb_polygon->rotate($rotate_vector->[0][0], $m->{hex_center}); $bounding_box = $bb_polygon->bounding_box; - # $bounding_box->y_min and $bounding_box->y_max represent the displacement between new bounding box offset and old one - $bounding_box->extents->[X][MIN] -= $bounding_box->x_min % $hex_width; - $bounding_box->extents->[Y][MAX] -= $bounding_box->y_min % $pattern_height; + + # 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}; } - my @polygons = (); my $x = $bounding_box->x_min; while ($x <= $bounding_box->x_max) { my $p = []; - my @x = ($x + $x_offset, $x + $distance - $x_offset); + my @x = ($x + $m->{x_offset}, $x + $m->{distance} - $m->{x_offset}); for (1..2) { @$p = reverse @$p; # turn first half upside down my @p = (); - for (my $y = $bounding_box->x_min; $y <= $bounding_box->y_max; $y += $y_short + $hex_side + $y_short + $hex_side) { + 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}) { push @$p, - [ $x[1], $y + $y_offset ], - [ $x[0], $y + $y_short - $y_offset ], - [ $x[0], $y + $y_short + $hex_side + $y_offset ], - [ $x[1], $y + $y_short + $hex_side + $y_short - $y_offset ], - [ $x[1], $y + $y_short + $hex_side + $y_short + $hex_side + $y_offset ]; + [ $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} ]; } - @x = map $_ + $distance, reverse @x; # draw symmetrical pattern - $x += $distance; + @x = map $_ + $m->{distance}, reverse @x; # draw symmetrical pattern + $x += $m->{distance}; } push @polygons, Slic3r::Polygon->new($p); } - $_->rotate(-$rotate_vector->[0][0], $hex_center) for @polygons; - $self->cache->{$cache_id} = [@polygons]; + $_->rotate(-$rotate_vector->[0][0], $m->{hex_center}) for @polygons; } # consider polygons as polylines without re-appending the initial point: @@ -84,8 +82,8 @@ sub fill_surface { # path is more straight my @paths = map Slic3r::Polyline->new($_), @{ Boost::Geometry::Utils::polygon_multi_linestring_intersection( - $expolygon, - $self->cache->{$cache_id}, + $surface->expolygon, + \@polygons, ) }; return { flow_spacing => $params{flow_spacing} },