STL.pm 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. package Slic3r::STL;
  2. use Moo;
  3. use Slic3r::Geometry qw(X Y Z triangle_normal);
  4. use XXX;
  5. sub read_file {
  6. my $self = shift;
  7. my ($file) = @_;
  8. open my $fh, '<', $file or die "Failed to open $file\n";
  9. # let's detect whether file is ASCII or binary
  10. my $mode;
  11. {
  12. my $size = +(stat $fh)[7];
  13. $mode = 'ascii' if $size < 80 + 4;
  14. # skip binary header
  15. seek $fh, 80, 0;
  16. read $fh, my $buf, 4;
  17. my $triangle_count = unpack 'L', $buf;
  18. die "STL file seems invalid, could not read facet count\n" if !defined $triangle_count;
  19. my $expected_size =
  20. + 80 # header
  21. + 4 # count
  22. + $triangle_count * (
  23. + 4 # normal, pt,pt,pt (vectors)
  24. * 4 # bytes per value
  25. * 3 # values per vector
  26. + 2 # the trailing 'short'
  27. );
  28. $mode = ($size == $expected_size) ? 'binary' : 'ascii';
  29. }
  30. my $facets = [];
  31. $mode eq 'ascii'
  32. ? _read_ascii($fh, $facets)
  33. : _read_binary($fh, $facets);
  34. close $fh;
  35. my $vertices = [];
  36. {
  37. my %vertices_map = (); # given a vertex's coordinates, what's its index?
  38. my @vertices_facets = (); # given a vertex index, what are the indexes of its tangent facets?
  39. for (my $f = 0; $f <= $#$facets; $f++) {
  40. for (1..3) {
  41. my $point_id = join ',', @{$facets->[$f][$_]};
  42. if (exists $vertices_map{$point_id}) {
  43. $facets->[$f][$_] = $vertices_map{$point_id};
  44. push @{$vertices_facets[$facets->[$f][$_]]}, $f;
  45. } else {
  46. push @$vertices, $facets->[$f][$_];
  47. $facets->[$f][$_] = $vertices_map{$point_id} = $#$vertices;
  48. $vertices_facets[$#$vertices] = [$f];
  49. }
  50. }
  51. }
  52. # The following loop checks that @vertices_facets only groups facets that
  53. # are really connected together (i.e. neighbors or sharing neighbors);
  54. # in other words it takes care of multiple vertices occupying the same
  55. # point in space. It enforces topological correctness which is needed by
  56. # the slicing algorithm.
  57. # I'm keeping it disabled until I find a good test case.
  58. if (0) {
  59. my $vertices_count = $#$vertices; # store it to avoid processing newly created vertices
  60. for (my $v = 0; $v <= $vertices_count; $v++) {
  61. my $more_than_one_vertex_in_this_point = 0;
  62. while (@{$vertices_facets[$v]}) {
  63. my @facets_indexes = @{$vertices_facets[$v]};
  64. @{$vertices_facets[$v]} = ();
  65. my @this_f = shift @facets_indexes;
  66. CYCLE: while (@facets_indexes && @this_f) {
  67. # look for a facet that is connected to $this_f[-1] and whose common line contains $v
  68. my @other_vertices_indexes = grep $_ != $v, @{$facets->[$this_f[-1]]}[1..3];
  69. OTHER: for my $other_f (@facets_indexes) {
  70. # facet is connected if it shares one more point
  71. for (grep $_ != $v, @{$facets->[$other_f]}[1..3]) {
  72. if ($_ ~~ @other_vertices_indexes) {
  73. #printf "facet %d is connected to $other_f (sharing vertices $v and $_)\n", $this_f[-1];
  74. # TODO: we should ensure that the common edge has a different orientation
  75. # for each of the two adjacent facets
  76. push @this_f, $other_f;
  77. @facets_indexes = grep $_ != $other_f, @facets_indexes;
  78. next CYCLE;
  79. }
  80. }
  81. }
  82. # if we're here, then we couldn't find any facet connected to $this_f[-1]
  83. # so we should move this one to a different cluster (that is, a new vertex)
  84. # (or ignore it if it turns to be a non-manifold facet)
  85. if (@this_f > 1) {
  86. push @{$vertices_facets[$v]}, $this_f[-1];
  87. pop @this_f;
  88. $more_than_one_vertex_in_this_point++;
  89. } else {
  90. last CYCLE;
  91. }
  92. }
  93. if ($more_than_one_vertex_in_this_point) {
  94. Slic3r::debugf " more than one vertex in the same point\n";
  95. push @$vertices, $vertices->[$v];
  96. for my $f (@this_f) {
  97. $facets->[$f][$_] = $#$vertices for grep $facets->[$f][$_] == $v, 1..3;
  98. }
  99. }
  100. }
  101. }
  102. }
  103. }
  104. return Slic3r::TriangleMesh->new(vertices => $vertices, facets => $facets);
  105. }
  106. sub _read_ascii {
  107. my ($fh, $facets) = @_;
  108. my $point_re = qr/([^ ]+)\s+([^ ]+)\s+([^ ]+)\s*$/;
  109. my $facet;
  110. seek $fh, 0, 0;
  111. while (my $_ = <$fh>) {
  112. s/\R+$//;
  113. if (!$facet) {
  114. /^\s*facet\s+normal\s+$point_re/ or next;
  115. $facet = [ [$1, $2, $3] ];
  116. } else {
  117. if (/^\s*endfacet/) {
  118. push @$facets, $facet;
  119. undef $facet;
  120. } else {
  121. /^\s*vertex\s+$point_re/ or next;
  122. push @$facet, [map $_ * 1, $1, $2, $3];
  123. }
  124. }
  125. }
  126. if ($facet) {
  127. die "STL file seems invalid\n";
  128. }
  129. }
  130. sub _read_binary {
  131. my ($fh, $facets) = @_;
  132. die "bigfloat" unless length(pack "f", 1) == 4;
  133. binmode $fh;
  134. seek $fh, 80 + 4, 0;
  135. while (read $fh, my $_, 4*4*3+2) {
  136. my @v = unpack '(f<3)4';
  137. push @$facets, [ [@v[0..2]], [@v[3..5]], [@v[6..8]], [@v[9..11]] ];
  138. }
  139. }
  140. sub write_file {
  141. my $self = shift;
  142. my ($file, $mesh, $binary) = @_;
  143. open my $fh, '>', $file;
  144. $binary
  145. ? _write_binary($fh, $mesh)
  146. : _write_ascii($fh, $mesh);
  147. close $fh;
  148. }
  149. sub _write_binary {
  150. my ($fh, $mesh) = @_;
  151. die "bigfloat" unless length(pack "f", 1) == 4;
  152. binmode $fh;
  153. print $fh pack 'x80';
  154. print $fh pack 'L', scalar(@{$mesh->facets});
  155. foreach my $facet (@{$mesh->facets}) {
  156. print $fh pack '(f<3)4S',
  157. @{_facet_normal($mesh, $facet)},
  158. (map @{$mesh->vertices->[$_]}, @$facet[1,2,3]),
  159. 0;
  160. }
  161. }
  162. sub _write_ascii {
  163. my ($fh, $mesh) = @_;
  164. printf $fh "solid\n";
  165. foreach my $facet (@{$mesh->facets}) {
  166. printf $fh " facet normal %f %f %f\n", @{_facet_normal($mesh, $facet)};
  167. printf $fh " outer loop\n";
  168. printf $fh " vertex %f %f %f\n", @{$mesh->vertices->[$_]} for @$facet[1,2,3];
  169. printf $fh " endloop\n";
  170. printf $fh " endfacet\n";
  171. }
  172. printf $fh "endsolid\n";
  173. }
  174. sub _facet_normal {
  175. my ($mesh, $facet) = @_;
  176. return triangle_normal(map $mesh->vertices->[$_], @$facet[1,2,3]);
  177. }
  178. 1;