Rectilinear.pm 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. package Slic3r::Fill::Rectilinear;
  2. use Moo;
  3. extends 'Slic3r::Fill::Base';
  4. has 'cache' => (is => 'rw', default => sub {{}});
  5. use Slic3r::Geometry qw(A B X Y MIN scale unscale scaled_epsilon);
  6. sub fill_surface {
  7. my $self = shift;
  8. my ($surface, %params) = @_;
  9. # rotate polygons so that we can work with vertical lines here
  10. my $expolygon = $surface->expolygon->clone;
  11. my $rotate_vector = $self->infill_direction($surface);
  12. $self->rotate_points($expolygon, $rotate_vector);
  13. my $flow_spacing = $params{flow_spacing};
  14. my $min_spacing = scale $params{flow_spacing};
  15. my $line_spacing = $min_spacing / $params{density};
  16. my $line_oscillation = $line_spacing - $min_spacing;
  17. my $is_line_pattern = $self->isa('Slic3r::Fill::Line');
  18. my $bounding_box = $expolygon->bounding_box;
  19. # define flow spacing according to requested density
  20. if ($params{density} == 1 && !$params{dont_adjust}) {
  21. $line_spacing = $self->adjust_solid_spacing(
  22. width => $bounding_box->size->[X],
  23. distance => $line_spacing,
  24. );
  25. $flow_spacing = unscale $line_spacing;
  26. } else {
  27. # extend bounding box so that our pattern will be aligned with other layers
  28. $bounding_box->extents->[X][MIN] -= $bounding_box->x_min % $line_spacing;
  29. $bounding_box->extents->[Y][MIN] -= $bounding_box->y_min % $line_spacing;
  30. }
  31. # generate the basic pattern
  32. my $i = 0;
  33. my $x = $bounding_box->x_min;
  34. my $x_max = $bounding_box->x_max + scaled_epsilon;
  35. my @vertical_lines = ();
  36. while ($x <= $x_max) {
  37. my $vertical_line = [ [$x, $bounding_box->y_max], [$x, $bounding_box->y_min] ];
  38. if ($is_line_pattern && $i % 2) {
  39. $vertical_line->[A][X] += $line_oscillation;
  40. $vertical_line->[B][X] -= $line_oscillation;
  41. }
  42. push @vertical_lines, $vertical_line;
  43. $i++;
  44. $x += $line_spacing;
  45. }
  46. # clip paths against a slightly offsetted expolygon, so that the first and last paths
  47. # are kept even if the expolygon has vertical sides
  48. # the minimum offset for preventing edge lines from being clipped is scaled_epsilon;
  49. # however we use a larger offset to support expolygons with slightly skewed sides and
  50. # not perfectly straight
  51. my @polylines = map Slic3r::Polyline->new(@$_),
  52. @{ Boost::Geometry::Utils::multi_polygon_multi_linestring_intersection(
  53. [ map $_->pp, @{$expolygon->offset_ex($line_spacing*0.05)} ],
  54. [ @vertical_lines ],
  55. ) };
  56. # connect lines
  57. unless ($params{dont_connect}) {
  58. my ($expolygon_off) = @{$expolygon->offset_ex(scale $params{flow_spacing}/2)};
  59. my $collection = Slic3r::Polyline::Collection->new(@polylines);
  60. @polylines = ();
  61. my $tolerance = 10 * scaled_epsilon;
  62. my $diagonal_distance = $line_spacing * 2;
  63. my $can_connect = $is_line_pattern
  64. ? sub {
  65. ($_[X] >= ($line_spacing - $line_oscillation) - $tolerance) && ($_[X] <= ($line_spacing + $line_oscillation) + $tolerance)
  66. && $_[Y] <= $diagonal_distance
  67. }
  68. : sub { $_[X] <= $diagonal_distance && $_[Y] <= $diagonal_distance };
  69. foreach my $polyline (@{$collection->chained_path(0)}) {
  70. if (@polylines) {
  71. my $first_point = $polyline->first_point;
  72. my $last_point = $polylines[-1]->last_point;
  73. my @distance = map abs($first_point->$_ - $last_point->$_), qw(x y);
  74. # TODO: we should also check that both points are on a fill_boundary to avoid
  75. # connecting paths on the boundaries of internal regions
  76. if ($can_connect->(@distance) && $expolygon_off->encloses_line(Slic3r::Line->new($last_point, $first_point), $tolerance)) {
  77. $polylines[-1]->append_polyline($polyline);
  78. next;
  79. }
  80. }
  81. # make a clone before $collection goes out of scope
  82. push @polylines, $polyline->clone;
  83. }
  84. }
  85. # paths must be rotated back
  86. $self->rotate_points_back(\@polylines, $rotate_vector);
  87. return { flow_spacing => $flow_spacing }, @polylines;
  88. }
  89. 1;