combineinfill.t 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. use Test::More;
  2. use strict;
  3. use warnings;
  4. BEGIN {
  5. use FindBin;
  6. use lib "$FindBin::Bin/../lib";
  7. use local::lib "$FindBin::Bin/../local-lib";
  8. }
  9. use List::Util qw(first);
  10. use Slic3r;
  11. use Slic3r::Surface ':types';
  12. use Slic3r::Test;
  13. plan tests => 8;
  14. {
  15. my $test = sub {
  16. my ($config) = @_;
  17. my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
  18. ok my $gcode = Slic3r::Test::gcode($print), "infill_every_layers does not crash";
  19. my $tool = undef;
  20. my %layers = (); # layer_z => 1
  21. my %layer_infill = (); # layer_z => has_infill
  22. Slic3r::GCode::Reader->new->parse($gcode, sub {
  23. my ($self, $cmd, $args, $info) = @_;
  24. if ($cmd =~ /^T(\d+)/) {
  25. $tool = $1;
  26. } elsif ($cmd eq 'G1' && $info->{extruding} && $info->{dist_XY} > 0 && $tool != $config->support_material_extruder-1) {
  27. $layer_infill{$self->Z} //= 0;
  28. if ($tool == $config->infill_extruder-1) {
  29. $layer_infill{$self->Z} = 1;
  30. }
  31. }
  32. # Previously, all G-code commands had a fixed number of decimal points with means with redundant zeros after decimal points.
  33. # We changed this behavior and got rid of these redundant padding zeros, which caused this test to fail
  34. # because the position in Z-axis is compared as a string, and previously, G-code contained the following two commands:
  35. # "G1 Z5 F5000 ; lift nozzle"
  36. # "G1 Z5.000 F7800.000"
  37. # That has a different Z-axis position from the view of string comparisons of floating-point numbers.
  38. # To correct the computation of the number of printed layers, even in the case of string comparisons of floating-point numbers,
  39. # we filtered out the G-code command with the commend 'lift nozzle'.
  40. $layers{$args->{Z}} = 1 if $cmd eq 'G1' && $info->{dist_Z} && index($info->{comment}, 'lift nozzle') == -1;
  41. });
  42. my $layers_with_perimeters = scalar(keys %layer_infill);
  43. my $layers_with_infill = grep $_ > 0, values %layer_infill;
  44. is scalar(keys %layers), $layers_with_perimeters+$config->raft_layers, 'expected number of layers';
  45. if ($config->raft_layers == 0) {
  46. # first infill layer printed directly on print bed is not combined, so we don't consider it.
  47. $layers_with_infill--;
  48. $layers_with_perimeters--;
  49. }
  50. # we expect that infill is generated for half the number of combined layers
  51. # plus for each single layer that was not combined (remainder)
  52. is $layers_with_infill,
  53. int($layers_with_perimeters/$config->infill_every_layers) + ($layers_with_perimeters % $config->infill_every_layers),
  54. 'infill is only present in correct number of layers';
  55. };
  56. my $config = Slic3r::Config::new_from_defaults;
  57. $config->set('layer_height', 0.2);
  58. $config->set('first_layer_height', 0.2);
  59. $config->set('nozzle_diameter', [0.5,0.5,0.5,0.5]);
  60. $config->set('infill_every_layers', 2);
  61. $config->set('perimeter_extruder', 1);
  62. $config->set('infill_extruder', 2);
  63. $config->set('wipe_into_infill', 0);
  64. $config->set('support_material_extruder', 3);
  65. $config->set('support_material_interface_extruder', 3);
  66. $config->set('top_solid_layers', 0);
  67. $config->set('bottom_solid_layers', 0);
  68. $test->($config);
  69. $config->set('skirts', 0); # prevent usage of perimeter_extruder in raft layers
  70. $config->set('raft_layers', 5);
  71. $test->($config);
  72. }
  73. {
  74. my $config = Slic3r::Config::new_from_defaults;
  75. $config->set('layer_height', 0.2);
  76. $config->set('first_layer_height', 0.2);
  77. $config->set('nozzle_diameter', [0.5]);
  78. $config->set('infill_every_layers', 2);
  79. my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
  80. $print->process;
  81. ok defined(first { @{$_->get_region(0)->fill_surfaces->filter_by_type(S_TYPE_INTERNALVOID)} > 0 }
  82. @{$print->print->get_object(0)->layers}),
  83. 'infill combination produces internal void surfaces';
  84. # we disable combination after infill has been generated
  85. $config->set('infill_every_layers', 1);
  86. $print->apply($print->print->model->clone, $config);
  87. $print->process;
  88. ok !(defined first { @{$_->get_region(0)->fill_surfaces} == 0 }
  89. @{$print->print->get_object(0)->layers}),
  90. 'infill combination is idempotent';
  91. }
  92. # the following needs to be adapted to the new API
  93. if (0) {
  94. my $config = Slic3r::Config::new_from_defaults;
  95. $config->set('skirts', 0);
  96. $config->set('solid_layers', 0);
  97. $config->set('bottom_solid_layers', 0);
  98. $config->set('top_solid_layers', 0);
  99. $config->set('infill_every_layers', 6);
  100. $config->set('layer_height', 0.06);
  101. $config->set('perimeters', 1);
  102. my $test = sub {
  103. my ($shift) = @_;
  104. my $self = Slic3r::Test::init_print('20mm_cube', config => $config);
  105. $shift /= &Slic3r::SCALING_FACTOR;
  106. my $scale = 4; # make room for fat infill lines with low layer height
  107. # Put a slope on the box's sides by shifting x and y coords by $tilt * (z / boxheight).
  108. # The test here is to put such a slight slope on the walls that it should
  109. # not trigger any extra fill on fill layers that should be empty when
  110. # combine infill is enabled.
  111. $_->[0] += $shift * ($_->[2] / (20 / &Slic3r::SCALING_FACTOR)) for @{$self->objects->[0]->meshes->[0]->vertices};
  112. $_->[1] += $shift * ($_->[2] / (20 / &Slic3r::SCALING_FACTOR)) for @{$self->objects->[0]->meshes->[0]->vertices};
  113. $_ = [$_->[0]*$scale, $_->[1]*$scale, $_->[2]] for @{$self->objects->[0]->meshes->[0]->vertices};
  114. # copy of Print::export_gcode() up to the point
  115. # after fill surfaces are combined
  116. $_->slice for @{$self->objects};
  117. $_->make_perimeters for @{$self->objects};
  118. $_->detect_surfaces_type for @{$self->objects};
  119. $_->prepare_fill_surfaces for map @{$_->regions}, map @{$_->layers}, @{$self->objects};
  120. $_->process_external_surfaces for map @{$_->regions}, map @{$_->layers}, @{$self->objects};
  121. $_->discover_horizontal_shells for @{$self->objects};
  122. $_->combine_infill for @{$self->objects};
  123. # Only layers with id % 6 == 0 should have fill.
  124. my $spurious_infill = 0;
  125. foreach my $layer (map @{$_->layers}, @{$self->objects}) {
  126. ++$spurious_infill if ($layer->id % 6 && grep @{$_->fill_surfaces} > 0, @{$layer->regions});
  127. }
  128. $spurious_infill -= scalar(@{$self->objects->[0]->layers} - 1) % 6;
  129. fail "spurious fill surfaces found on layers that should have none (walls " . sprintf("%.4f", Slic3r::Geometry::rad2deg(atan2($shift, 20/&Slic3r::SCALING_FACTOR))) . " degrees off vertical)"
  130. unless $spurious_infill == 0;
  131. 1;
  132. };
  133. # Test with mm skew offsets for the top of the 20mm-high box
  134. for my $shift (0, 0.0001, 1) {
  135. ok $test->($shift), "no spurious fill surfaces with box walls " . sprintf("%.4f",Slic3r::Geometry::rad2deg(atan2($shift, 20))) . " degrees off of vertical";
  136. }
  137. }
  138. __END__