wireframe.pl 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. #!/usr/bin/perl
  2. # This script exports experimental G-code for wireframe printing
  3. # (inspired by the brilliant WirePrint concept)
  4. use strict;
  5. use warnings;
  6. BEGIN {
  7. use FindBin;
  8. use lib "$FindBin::Bin/../lib";
  9. use local::lib "$FindBin::Bin/../local-lib";
  10. }
  11. use Getopt::Long qw(:config no_auto_abbrev);
  12. use Slic3r;
  13. use Slic3r::ExtrusionPath ':roles';
  14. use Slic3r::Geometry qw(scale unscale X Y PI);
  15. my %opt = (
  16. step_height => 5,
  17. nozzle_angle => 30,
  18. nozzle_width => 10,
  19. first_layer_height => 0.3,
  20. );
  21. {
  22. my %options = (
  23. 'help' => sub { usage() },
  24. 'output|o=s' => \$opt{output_file},
  25. 'step-height|h=f' => \$opt{step_height},
  26. 'nozzle-angle|a=f' => \$opt{nozzle_angle},
  27. 'nozzle-width|w=f' => \$opt{nozzle_width},
  28. 'first-layer-height=f' => \$opt{first_layer_height},
  29. );
  30. GetOptions(%options) or usage(1);
  31. $opt{output_file} or usage(1);
  32. $ARGV[0] or usage(1);
  33. }
  34. {
  35. # load model
  36. my $model = Slic3r::Model->read_from_file($ARGV[0]);
  37. $model->add_default_instances;
  38. $model->center_instances_around_point(Slic3r::Pointf->new(100,100));
  39. my $mesh = $model->mesh;
  40. $mesh->translate(0, 0, -$mesh->bounding_box->z_min);
  41. # get slices
  42. my @z = ();
  43. my $z_max = $mesh->bounding_box->z_max;
  44. for (my $z = $opt{first_layer_height}; $z <= $z_max; $z += $opt{step_height}) {
  45. push @z, $z;
  46. }
  47. my @slices = @{$mesh->slice(\@z)};
  48. my $flow = Slic3r::Flow->new(
  49. width => 0.35,
  50. height => 0.35,
  51. nozzle_diameter => 0.35,
  52. bridge => 1,
  53. );
  54. my $config = Slic3r::Config::Print->new;
  55. $config->set('gcode_comments', 1);
  56. open my $fh, '>', $opt{output_file};
  57. my $gcodegen = Slic3r::GCode->new(
  58. enable_loop_clipping => 0, # better bonding
  59. );
  60. $gcodegen->apply_print_config($config);
  61. $gcodegen->set_extruders([0]);
  62. print $fh $gcodegen->set_extruder(0);
  63. print $fh $gcodegen->writer->preamble;
  64. my $e = $gcodegen->writer->extruder->e_per_mm3 * $flow->mm3_per_mm;
  65. foreach my $layer_id (0..$#z) {
  66. my $z = $z[$layer_id];
  67. foreach my $island (@{$slices[$layer_id]}) {
  68. foreach my $polygon (@$island) {
  69. if ($layer_id > 0) {
  70. # find the lower polygon that we want to connect to this one
  71. my $lower = $slices[$layer_id-1]->[0]->contour; # 't was easy, wasn't it?
  72. my $lower_z = $z[$layer_id-1];
  73. {
  74. my @points = ();
  75. # keep all points with strong angles
  76. {
  77. my @pp = @$polygon;
  78. foreach my $i (0..$#pp) {
  79. push @points, $pp[$i-1] if abs($pp[$i-1]->ccw_angle($pp[$i-2], $pp[$i]) - PI) > PI/3;
  80. }
  81. }
  82. $polygon = Slic3r::Polygon->new(@points);
  83. }
  84. #$polygon = Slic3r::Polygon->new(@{$polygon->split_at_first_point->equally_spaced_points(scale $opt{nozzle_width})});
  85. # find vertical lines
  86. my @vertical = ();
  87. foreach my $point (@{$polygon}) {
  88. push @vertical, Slic3r::Line->new($point->projection_onto_polygon($lower), $point);
  89. }
  90. next if !@vertical;
  91. my @points = ();
  92. foreach my $line (@vertical) {
  93. push @points, Slic3r::Pointf3->new(
  94. unscale($line->a->x),
  95. unscale($line->a->y), #))
  96. $lower_z,
  97. );
  98. push @points, Slic3r::Pointf3->new(
  99. unscale($line->b->x),
  100. unscale($line->b->y), #))
  101. $z,
  102. );
  103. }
  104. # reappend first point as destination of the last diagonal segment
  105. push @points, Slic3r::Pointf3->new(
  106. unscale($vertical[0]->a->x),
  107. unscale($vertical[0]->a->y), #))
  108. $lower_z,
  109. );
  110. # move to the position of the first vertical line
  111. print $fh $gcodegen->writer->travel_to_xyz(shift @points);
  112. # extrude segments
  113. foreach my $point (@points) {
  114. print $fh $gcodegen->writer->extrude_to_xyz($point, $e * $gcodegen->writer->get_position->distance_to($point));
  115. }
  116. }
  117. }
  118. print $fh $gcodegen->writer->travel_to_z($z);
  119. foreach my $polygon (@$island) {
  120. #my $polyline = $polygon->split_at_vertex(Slic3r::Point->new_scale(@{$gcodegen->writer->get_position}[0,1]));
  121. my $polyline = $polygon->split_at_first_point;
  122. print $fh $gcodegen->writer->travel_to_xy(Slic3r::Pointf->new_unscale(@{ $polyline->first_point }), "move to first contour point");
  123. foreach my $line (@{$polyline->lines}) {
  124. my $point = Slic3r::Pointf->new_unscale(@{ $line->b });
  125. print $fh $gcodegen->writer->extrude_to_xy($point, $e * unscale($line->length));
  126. }
  127. }
  128. }
  129. }
  130. close $fh;
  131. }
  132. sub usage {
  133. my ($exit_code) = @_;
  134. print <<"EOF";
  135. Usage: wireframe.pl [ OPTIONS ] file.stl
  136. --help Output this usage screen and exit
  137. --output, -o Write to the specified file
  138. --step-height, -h Use the specified step height
  139. --nozzle-angle, -a Max nozzle angle
  140. --nozzle-width, -w External nozzle diameter
  141. EOF
  142. exit ($exit_code || 0);
  143. }
  144. __END__