Fill.pm 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. package Slic3r::Fill;
  2. use Moo;
  3. use Slic3r::Fill::ArchimedeanChords;
  4. use Slic3r::Fill::Base;
  5. use Slic3r::Fill::Concentric;
  6. use Slic3r::Fill::Flowsnake;
  7. use Slic3r::Fill::HilbertCurve;
  8. use Slic3r::Fill::Honeycomb;
  9. use Slic3r::Fill::Line;
  10. use Slic3r::Fill::OctagramSpiral;
  11. use Slic3r::Fill::PlanePath;
  12. use Slic3r::Fill::Rectilinear;
  13. use Slic3r::ExtrusionPath ':roles';
  14. use Slic3r::Geometry qw(X Y scale shortest_path);
  15. use Slic3r::Geometry::Clipper qw(union_ex diff_ex);
  16. use Slic3r::Surface ':types';
  17. has 'print' => (is => 'ro', required => 1);
  18. has 'max_print_dimension' => (is => 'rw');
  19. has 'fillers' => (is => 'rw', default => sub { {} });
  20. our %FillTypes = (
  21. archimedeanchords => 'Slic3r::Fill::ArchimedeanChords',
  22. rectilinear => 'Slic3r::Fill::Rectilinear',
  23. flowsnake => 'Slic3r::Fill::Flowsnake',
  24. octagramspiral => 'Slic3r::Fill::OctagramSpiral',
  25. hilbertcurve => 'Slic3r::Fill::HilbertCurve',
  26. line => 'Slic3r::Fill::Line',
  27. concentric => 'Slic3r::Fill::Concentric',
  28. honeycomb => 'Slic3r::Fill::Honeycomb',
  29. );
  30. sub BUILD {
  31. my $self = shift;
  32. my $print_size = $self->print->size;
  33. my $max_print_dimension = ($print_size->[X] > $print_size->[Y] ? $print_size->[X] : $print_size->[Y]) * sqrt(2);
  34. $self->max_print_dimension($max_print_dimension);
  35. $self->filler($_) for ('rectilinear', $Slic3r::fill_pattern, $Slic3r::solid_fill_pattern);
  36. }
  37. sub filler {
  38. my $self = shift;
  39. my ($filler) = @_;
  40. if (!$self->fillers->{$filler}) {
  41. $self->fillers->{$filler} = $FillTypes{$filler}->new(print => $self->print);
  42. $self->fillers->{$filler}->max_print_dimension($self->max_print_dimension);
  43. }
  44. return $self->fillers->{$filler};
  45. }
  46. sub make_fill {
  47. my $self = shift;
  48. my ($layer) = @_;
  49. $_->layer($layer) for values %{$self->fillers};
  50. Slic3r::debugf "Filling layer %d:\n", $layer->id;
  51. # merge overlapping surfaces
  52. my @surfaces = ();
  53. {
  54. my @surfaces_with_bridge_angle = grep defined $_->bridge_angle, @{$layer->fill_surfaces};
  55. # give priority to bridges
  56. my @groups = Slic3r::Surface->group({merge_solid => 1}, @{$layer->fill_surfaces});
  57. @groups = sort { defined $a->[0]->bridge_angle ? -1 : 0 } @groups;
  58. foreach my $group (@groups) {
  59. my $union = union_ex([ map $_->p, @$group ], undef, 1);
  60. # subtract surfaces having a defined bridge_angle from any other
  61. if (@surfaces_with_bridge_angle && !defined $group->[0]->bridge_angle) {
  62. $union = diff_ex(
  63. [ map @$_, @$union ],
  64. [ map $_->p, @surfaces_with_bridge_angle ],
  65. 1,
  66. );
  67. }
  68. # subtract any other surface already processed
  69. $union = diff_ex(
  70. [ map @$_, @$union ],
  71. [ map $_->p, @surfaces ],
  72. 1,
  73. );
  74. push @surfaces, map Slic3r::Surface->new(
  75. expolygon => $_,
  76. surface_type => $group->[0]->surface_type,
  77. bridge_angle => $group->[0]->bridge_angle,
  78. depth_layers => $group->[0]->depth_layers,
  79. ), @$union;
  80. }
  81. }
  82. # add spacing between adjacent surfaces
  83. {
  84. my $distance = scale $layer->flow_spacing / 2;
  85. my @offsets = ();
  86. foreach my $surface (@surfaces) {
  87. my $expolygon = $surface->expolygon;
  88. my $diff = diff_ex(
  89. [ $expolygon->offset($distance) ],
  90. $expolygon,
  91. 1,
  92. );
  93. push @offsets, map @$_, @$diff;
  94. }
  95. my @new_surfaces = ();
  96. foreach my $surface (@surfaces) {
  97. my $diff = diff_ex(
  98. $surface->expolygon,
  99. [ @offsets ],
  100. );
  101. push @new_surfaces, map Slic3r::Surface->new(
  102. expolygon => $_,
  103. surface_type => $surface->surface_type,
  104. bridge_angle => $surface->bridge_angle,
  105. depth_layers => $surface->depth_layers,
  106. ), @$diff;
  107. }
  108. @surfaces = @new_surfaces;
  109. }
  110. # organize infill surfaces using a shortest path search
  111. @surfaces = @{shortest_path([
  112. map [ $_->contour->[0], $_ ], @surfaces,
  113. ])};
  114. my @fills = ();
  115. SURFACE: foreach my $surface (@surfaces) {
  116. my $filler = $Slic3r::fill_pattern;
  117. my $density = $Slic3r::fill_density;
  118. my $flow_spacing = $layer->flow_spacing;
  119. my $is_bridge = $layer->id > 0 && $surface->surface_type == S_TYPE_BOTTOM;
  120. my $is_solid = (grep { $surface->surface_type == $_ } S_TYPE_TOP, S_TYPE_BOTTOM, S_TYPE_INTERNALSOLID) ? 1 : 0;
  121. # force 100% density and rectilinear fill for external surfaces
  122. if ($surface->surface_type != S_TYPE_INTERNAL) {
  123. $density = 1;
  124. $filler = $Slic3r::solid_fill_pattern;
  125. if ($is_bridge) {
  126. $filler = 'rectilinear';
  127. $flow_spacing = sqrt($Slic3r::bridge_flow_ratio * ($Slic3r::nozzle_diameter**2));
  128. } elsif ($surface->surface_type == S_TYPE_INTERNALSOLID) {
  129. $filler = 'rectilinear';
  130. }
  131. } else {
  132. next SURFACE unless $density > 0;
  133. }
  134. my @paths = $self->fillers->{$filler}->fill_surface(
  135. $surface,
  136. density => $density,
  137. flow_spacing => $flow_spacing,
  138. );
  139. my $params = shift @paths;
  140. # save into layer
  141. push @fills, Slic3r::ExtrusionPath::Collection->new(
  142. paths => [
  143. map Slic3r::ExtrusionPath->new(
  144. polyline => Slic3r::Polyline->new(@$_),
  145. role => ($is_bridge ? EXTR_ROLE_BRIDGE
  146. : $is_solid ? EXTR_ROLE_SOLIDFILL
  147. : EXTR_ROLE_FILL),
  148. depth_layers => $surface->depth_layers,
  149. flow_spacing => $params->{flow_spacing},
  150. ), @paths,
  151. ],
  152. ) if @paths;
  153. }
  154. # add thin fill regions
  155. push @fills, Slic3r::ExtrusionPath::Collection->new(
  156. paths => [
  157. map {
  158. $_->isa('Slic3r::Polygon')
  159. ? Slic3r::ExtrusionLoop->new(polygon => $_, role => EXTR_ROLE_SOLIDFILL)->split_at($_->[0])
  160. : Slic3r::ExtrusionPath->new(polyline => $_, role => EXTR_ROLE_SOLIDFILL)
  161. } @{$layer->thin_fills},
  162. ],
  163. ) if @{$layer->thin_fills};
  164. return @fills;
  165. }
  166. 1;