Fill.pm 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  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 PI scale chained_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 'fillers' => (is => 'rw', default => sub { {} });
  19. our %FillTypes = (
  20. archimedeanchords => 'Slic3r::Fill::ArchimedeanChords',
  21. rectilinear => 'Slic3r::Fill::Rectilinear',
  22. flowsnake => 'Slic3r::Fill::Flowsnake',
  23. octagramspiral => 'Slic3r::Fill::OctagramSpiral',
  24. hilbertcurve => 'Slic3r::Fill::HilbertCurve',
  25. line => 'Slic3r::Fill::Line',
  26. concentric => 'Slic3r::Fill::Concentric',
  27. honeycomb => 'Slic3r::Fill::Honeycomb',
  28. );
  29. sub filler {
  30. my $self = shift;
  31. my ($filler) = @_;
  32. if (!ref $self) {
  33. return $FillTypes{$filler}->new;
  34. }
  35. if (!$self->fillers->{$filler}) {
  36. my $f = $self->fillers->{$filler} = $FillTypes{$filler}->new;
  37. $f->bounding_box([ $self->print->bounding_box ]) if $f->can('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. # merge adjacent surfaces
  46. # in case of bridge surfaces, the ones with defined angle will be attached to the ones
  47. # without any angle (shouldn't this logic be moved to process_external_surfaces()?)
  48. my @surfaces = ();
  49. {
  50. my @surfaces_with_bridge_angle = grep defined $_->bridge_angle, @{$layerm->fill_surfaces};
  51. # give priority to bridges
  52. my @groups = Slic3r::Surface->group({merge_solid => 1}, @{$layerm->fill_surfaces});
  53. @groups = sort { defined $a->[0]->bridge_angle ? -1 : 0 } @groups;
  54. foreach my $group (@groups) {
  55. my $union = union_ex([ map $_->p, @$group ], undef, 1);
  56. # subtract surfaces having a defined bridge_angle from any other
  57. if (@surfaces_with_bridge_angle && !defined $group->[0]->bridge_angle) {
  58. $union = diff_ex(
  59. [ map @$_, @$union ],
  60. [ map $_->p, @surfaces_with_bridge_angle ],
  61. 1,
  62. );
  63. }
  64. # subtract any other surface already processed
  65. $union = diff_ex(
  66. [ map @$_, @$union ],
  67. [ map $_->p, @surfaces ],
  68. 1,
  69. );
  70. push @surfaces, map Slic3r::Surface->new(
  71. expolygon => $_,
  72. surface_type => $group->[0]->surface_type,
  73. bridge_angle => $group->[0]->bridge_angle,
  74. depth_layers => $group->[0]->depth_layers,
  75. ), @$union;
  76. }
  77. }
  78. # add spacing between surfaces
  79. {
  80. my $distance = $layerm->infill_flow->scaled_spacing / 2;
  81. @surfaces = map $_->offset(-$distance), @surfaces;
  82. }
  83. my @fills = ();
  84. my @fills_ordering_points = ();
  85. SURFACE: foreach my $surface (@surfaces) {
  86. my $filler = $Slic3r::Config->fill_pattern;
  87. my $density = $Slic3r::Config->fill_density;
  88. my $flow_spacing = $layerm->infill_flow->spacing;
  89. my $is_bridge = $layerm->id > 0 && $surface->is_bridge;
  90. my $is_solid = $surface->is_solid;
  91. # force 100% density and rectilinear fill for external surfaces
  92. if ($surface->surface_type != S_TYPE_INTERNAL) {
  93. $density = 1;
  94. $filler = $Slic3r::Config->solid_fill_pattern;
  95. if ($is_bridge) {
  96. $filler = 'rectilinear';
  97. $flow_spacing = $layerm->extruders->{infill}->bridge_flow->spacing;
  98. } elsif ($surface->surface_type == S_TYPE_INTERNALSOLID) {
  99. $filler = 'rectilinear';
  100. }
  101. } else {
  102. next SURFACE unless $density > 0;
  103. }
  104. my @paths;
  105. {
  106. my $f = $self->filler($filler);
  107. $f->layer_id($layerm->id);
  108. @paths = $f->fill_surface(
  109. $surface,
  110. density => $density,
  111. flow_spacing => $flow_spacing,
  112. dont_adjust => $is_bridge,
  113. );
  114. }
  115. my $params = shift @paths;
  116. # ugly hack(tm) to get the right amount of flow (GCode.pm should be fixed)
  117. $params->{flow_spacing} = $layerm->extruders->{infill}->bridge_flow->width if $is_bridge;
  118. # save into layer
  119. next unless @paths;
  120. push @fills, Slic3r::ExtrusionPath::Collection->new(
  121. paths => [
  122. map Slic3r::ExtrusionPath->pack(
  123. polyline => Slic3r::Polyline->new(@$_),
  124. role => ($is_bridge
  125. ? EXTR_ROLE_BRIDGE
  126. : $is_solid
  127. ? ($surface->surface_type == S_TYPE_TOP ? EXTR_ROLE_TOPSOLIDFILL : EXTR_ROLE_SOLIDFILL)
  128. : EXTR_ROLE_FILL),
  129. height => $surface->depth_layers * $layerm->height,
  130. flow_spacing => $params->{flow_spacing} || (warn "Warning: no flow_spacing was returned by the infill engine, please report this to the developer\n"),
  131. ), @paths,
  132. ],
  133. );
  134. push @fills_ordering_points, $paths[0][0];
  135. }
  136. # add thin fill regions
  137. push @fills, @{$layerm->thin_fills};
  138. push @fills_ordering_points, map $_->unpack->points->[0], @{$layerm->thin_fills};
  139. # organize infill paths using a nearest-neighbor search
  140. @fills = @fills[ chained_path(\@fills_ordering_points) ];
  141. return @fills;
  142. }
  143. 1;