Fill.pm 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. package Slic3r::Fill;
  2. use Moo;
  3. use Slic3r::ExtrusionPath ':roles';
  4. use Slic3r::Fill::ArchimedeanChords;
  5. use Slic3r::Fill::Base;
  6. use Slic3r::Fill::Concentric;
  7. use Slic3r::Fill::Flowsnake;
  8. use Slic3r::Fill::HilbertCurve;
  9. use Slic3r::Fill::Honeycomb;
  10. use Slic3r::Fill::Line;
  11. use Slic3r::Fill::OctagramSpiral;
  12. use Slic3r::Fill::PlanePath;
  13. use Slic3r::Fill::Rectilinear;
  14. use Slic3r::Flow ':roles';
  15. use Slic3r::Geometry qw(X Y PI scale chained_path);
  16. use Slic3r::Geometry::Clipper qw(union union_ex diff diff_ex intersection_ex offset offset2);
  17. use Slic3r::Surface ':types';
  18. has 'bounding_box' => (is => 'ro', required => 0);
  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 filler {
  31. my $self = shift;
  32. my ($filler) = @_;
  33. if (!ref $self) {
  34. return $FillTypes{$filler}->new;
  35. }
  36. $self->fillers->{$filler} ||= $FillTypes{$filler}->new(
  37. bounding_box => $self->bounding_box,
  38. );
  39. return $self->fillers->{$filler};
  40. }
  41. sub make_fill {
  42. my $self = shift;
  43. my ($layerm) = @_;
  44. Slic3r::debugf "Filling layer %d:\n", $layerm->id;
  45. my $fill_density = $layerm->config->fill_density;
  46. my $infill_flow = $layerm->flow(FLOW_ROLE_INFILL);
  47. my $solid_infill_flow = $layerm->flow(FLOW_ROLE_SOLID_INFILL);
  48. my @surfaces = ();
  49. # merge adjacent surfaces
  50. # in case of bridge surfaces, the ones with defined angle will be attached to the ones
  51. # without any angle (shouldn't this logic be moved to process_external_surfaces()?)
  52. {
  53. my @surfaces_with_bridge_angle = grep defined $_->bridge_angle, @{$layerm->fill_surfaces};
  54. # give priority to bridges
  55. my @groups = sort { defined $a->[0]->bridge_angle ? -1 : 0 } @{$layerm->fill_surfaces->group(1)};
  56. foreach my $group (@groups) {
  57. my $union_p = union([ map $_->p, @$group ], 1);
  58. # subtract surfaces having a defined bridge_angle from any other
  59. if (@surfaces_with_bridge_angle && !defined $group->[0]->bridge_angle) {
  60. $union_p = diff(
  61. $union_p,
  62. [ map $_->p, @surfaces_with_bridge_angle ],
  63. 1,
  64. );
  65. }
  66. # subtract any other surface already processed
  67. my $union = diff_ex(
  68. $union_p,
  69. [ map $_->p, @surfaces ],
  70. 1,
  71. );
  72. push @surfaces, map $group->[0]->clone(expolygon => $_), @$union;
  73. }
  74. }
  75. # we need to detect any narrow surfaces that might collapse
  76. # when adding spacing below
  77. # such narrow surfaces are often generated in sloping walls
  78. # by bridge_over_infill() and combine_infill() as a result of the
  79. # subtraction of the combinable area from the layer infill area,
  80. # which leaves small areas near the perimeters
  81. # we are going to grow such regions by overlapping them with the void (if any)
  82. # TODO: detect and investigate whether there could be narrow regions without
  83. # any void neighbors
  84. my $distance_between_surfaces = $infill_flow->scaled_spacing * &Slic3r::INFILL_OVERLAP_OVER_SPACING;
  85. {
  86. my $collapsed = diff(
  87. [ map @{$_->expolygon}, @surfaces ],
  88. offset2([ map @{$_->expolygon}, @surfaces ], -$distance_between_surfaces/2, +$distance_between_surfaces/2),
  89. 1,
  90. );
  91. push @surfaces, map Slic3r::Surface->new(
  92. expolygon => $_,
  93. surface_type => S_TYPE_INTERNALSOLID,
  94. ), @{intersection_ex(
  95. offset($collapsed, $distance_between_surfaces),
  96. [
  97. (map @{$_->expolygon}, grep $_->surface_type == S_TYPE_INTERNALVOID, @surfaces),
  98. (@$collapsed),
  99. ],
  100. 1,
  101. )};
  102. }
  103. # add spacing between surfaces
  104. @surfaces = map @{$_->offset(-$distance_between_surfaces / 2)}, @surfaces;
  105. if (0) {
  106. require "Slic3r/SVG.pm";
  107. Slic3r::SVG::output("fill_" . $layerm->print_z . ".svg",
  108. expolygons => [ map $_->expolygon, grep !$_->is_solid, @surfaces ],
  109. red_expolygons => [ map $_->expolygon, grep $_->is_solid, @surfaces ],
  110. );
  111. }
  112. my @fills = ();
  113. my @fills_ordering_points = ();
  114. SURFACE: foreach my $surface (@surfaces) {
  115. next if $surface->surface_type == S_TYPE_INTERNALVOID;
  116. my $filler = $layerm->config->fill_pattern;
  117. my $density = $fill_density;
  118. my $flow = ($surface->surface_type == S_TYPE_TOP)
  119. ? $layerm->flow(FLOW_ROLE_TOP_SOLID_INFILL)
  120. : $surface->is_solid
  121. ? $solid_infill_flow
  122. : $infill_flow;
  123. my $is_bridge = $layerm->id > 0 && $surface->is_bridge;
  124. my $is_solid = $surface->is_solid;
  125. # force 100% density and rectilinear fill for external surfaces
  126. if ($surface->surface_type != S_TYPE_INTERNAL) {
  127. $density = 1;
  128. $filler = $layerm->config->solid_fill_pattern;
  129. if ($is_bridge) {
  130. $filler = 'rectilinear';
  131. $flow = $layerm->flow(FLOW_ROLE_SOLID_INFILL, 1);
  132. } elsif ($surface->surface_type == S_TYPE_INTERNALSOLID) {
  133. $filler = 'rectilinear';
  134. }
  135. } else {
  136. next SURFACE unless $density > 0;
  137. }
  138. my $f = $self->filler($filler);
  139. $f->layer_id($layerm->id);
  140. $f->angle($layerm->config->fill_angle);
  141. my ($params, @polylines) = $f->fill_surface(
  142. $surface,
  143. density => $density,
  144. flow => $flow,
  145. );
  146. next unless @polylines;
  147. my $h = $surface->thickness;
  148. $h = $layerm->height if $h == -1;
  149. my $mm3_per_mm = $params->{flow}->mm3_per_mm($h);
  150. # save into layer
  151. push @fills, my $collection = Slic3r::ExtrusionPath::Collection->new;
  152. $collection->no_sort($params->{no_sort});
  153. $collection->append(
  154. map Slic3r::ExtrusionPath->new(
  155. polyline => $_,
  156. role => ($surface->surface_type == S_TYPE_INTERNALBRIDGE
  157. ? EXTR_ROLE_INTERNALBRIDGE
  158. : $is_bridge
  159. ? EXTR_ROLE_BRIDGE
  160. : $is_solid
  161. ? (($surface->surface_type == S_TYPE_TOP) ? EXTR_ROLE_TOPSOLIDFILL : EXTR_ROLE_SOLIDFILL)
  162. : EXTR_ROLE_FILL),
  163. mm3_per_mm => $mm3_per_mm,
  164. ), @polylines,
  165. );
  166. push @fills_ordering_points, $polylines[0]->first_point;
  167. }
  168. # add thin fill regions
  169. if ($layerm->thin_fills->count > 0) {
  170. push @fills, Slic3r::ExtrusionPath::Collection->new(@{$layerm->thin_fills});
  171. push @fills_ordering_points, $fills[-1]->first_point;
  172. }
  173. # organize infill paths using a nearest-neighbor search
  174. @fills = @fills[ @{chained_path(\@fills_ordering_points)} ];
  175. return @fills;
  176. }
  177. 1;