Honeycomb.pm 4.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. package Slic3r::Fill::Honeycomb;
  2. use Moo;
  3. extends 'Slic3r::Fill::Base';
  4. has 'cache' => (is => 'rw', default => sub {{}});
  5. use Slic3r::Geometry qw(PI X1 Y1 X2 Y2 X Y scale);
  6. use Slic3r::Geometry::Clipper qw(intersection_ex);
  7. sub angles () { [0, PI/3, PI/3*2] }
  8. sub fill_surface {
  9. my $self = shift;
  10. my ($surface, %params) = @_;
  11. # rotate polygons so that we can work with vertical lines here
  12. my $expolygon = $surface->expolygon->clone;
  13. my $rotate_vector = $self->infill_direction($surface);
  14. # infill math
  15. my $min_spacing = scale $params{flow_spacing};
  16. my $distance = $min_spacing / $params{density};
  17. my $overlap_distance = scale($self->layer ? $self->layer->flow->width : $Slic3r::flow->width) * 0.4;
  18. my $cache_id = sprintf "d%s_s%s_a%s",
  19. $params{density}, $params{flow_spacing}, $rotate_vector->[0][0];
  20. if (!$self->cache->{$cache_id}) {
  21. # hexagons math
  22. my $hex_side = $distance / (sqrt(3)/2);
  23. my $hex_width = $distance * 2; # $hex_width == $hex_side * sqrt(3);
  24. my $hex_height = $hex_side * 2;
  25. my $pattern_height = $hex_height + $hex_side;
  26. my $y_short = $distance * sqrt(3)/3;
  27. my $x_offset = $min_spacing / 2;
  28. my $y_offset = $x_offset * sqrt(3)/3;
  29. my $hex_center = Slic3r::Point->new($hex_width/2, $hex_side);
  30. # adjust actual bounding box to the nearest multiple of our hex pattern
  31. # and align it so that it matches across layers
  32. my $print_bounding_box = [ $self->print->bounding_box ];
  33. my $bounding_box = [ 0, 0, $print_bounding_box->[X2], $print_bounding_box->[Y2] ];
  34. {
  35. my $bb_polygon = Slic3r::Polygon->new([
  36. [ $bounding_box->[X1], $bounding_box->[Y1] ],
  37. [ $bounding_box->[X2], $bounding_box->[Y1] ],
  38. [ $bounding_box->[X2], $bounding_box->[Y2] ],
  39. [ $bounding_box->[X1], $bounding_box->[Y2] ],
  40. ]);
  41. $bb_polygon->rotate($rotate_vector->[0][0], $hex_center);
  42. $bounding_box = [ Slic3r::Geometry::bounding_box($bb_polygon) ];
  43. # $bounding_box->[X1] and [Y1] represent the displacement between new bounding box offset and old one
  44. $bounding_box->[X1] -= $bounding_box->[X1] % $hex_width;
  45. $bounding_box->[Y1] -= $bounding_box->[Y1] % $pattern_height;
  46. }
  47. my @polygons = ();
  48. my $x = $bounding_box->[X1];
  49. while ($x <= $bounding_box->[X2]) {
  50. my $p = [];
  51. my @x = ($x + $x_offset, $x + $distance - $x_offset);
  52. for (1..2) {
  53. @$p = reverse @$p; # turn first half upside down
  54. my @p = ();
  55. for (my $y = $bounding_box->[Y1]; $y <= $bounding_box->[Y2]; $y += $y_short + $hex_side + $y_short + $hex_side) {
  56. push @$p,
  57. [ $x[1], $y + $y_offset ],
  58. [ $x[0], $y + $y_short - $y_offset ],
  59. [ $x[0], $y + $y_short + $hex_side + $y_offset ],
  60. [ $x[1], $y + $y_short + $hex_side + $y_short - $y_offset ],
  61. [ $x[1], $y + $y_short + $hex_side + $y_short + $hex_side + $y_offset ];
  62. }
  63. @x = map $_ + $distance, reverse @x; # draw symmetrical pattern
  64. $x += $distance;
  65. }
  66. push @polygons, Slic3r::Polygon->new($p);
  67. }
  68. $_->rotate(-$rotate_vector->[0][0], $hex_center) for @polygons;
  69. $self->cache->{$cache_id} = [@polygons];
  70. }
  71. my @paths = map Slic3r::Polyline->new(@$_, $_->[0]), map @$_, @{intersection_ex(
  72. $self->cache->{$cache_id},
  73. [ map @$_, $expolygon->offset_ex($overlap_distance) ],
  74. )};
  75. my $collection = Slic3r::ExtrusionPath::Collection->new(
  76. paths => [ map Slic3r::ExtrusionPath->pack(polyline => $_, role => -1), @paths ],
  77. );
  78. return {}, map $_->polyline, $collection->shortest_path;
  79. }
  80. 1;