2012-02-25 16:35:25 +00:00
|
|
|
package Slic3r::Format::STL;
|
2011-09-06 09:50:43 +00:00
|
|
|
use Moo;
|
2011-09-01 19:06:28 +00:00
|
|
|
|
2012-02-19 14:45:27 +00:00
|
|
|
use Slic3r::Geometry qw(X Y Z triangle_normal);
|
2011-09-01 19:06:28 +00:00
|
|
|
|
2011-10-12 08:47:26 +00:00
|
|
|
sub read_file {
|
|
|
|
my $self = shift;
|
|
|
|
my ($file) = @_;
|
|
|
|
|
2013-01-13 09:18:34 +00:00
|
|
|
Slic3r::open(\my $fh, '<', $file) or die "Failed to open $file\n";
|
2011-10-12 08:47:26 +00:00
|
|
|
|
|
|
|
# let's detect whether file is ASCII or binary
|
|
|
|
my $mode;
|
|
|
|
{
|
|
|
|
my $size = +(stat $fh)[7];
|
|
|
|
$mode = 'ascii' if $size < 80 + 4;
|
|
|
|
|
|
|
|
# skip binary header
|
|
|
|
seek $fh, 80, 0;
|
|
|
|
read $fh, my $buf, 4;
|
|
|
|
my $triangle_count = unpack 'L', $buf;
|
2011-12-18 09:50:55 +00:00
|
|
|
die "STL file seems invalid, could not read facet count\n" if !defined $triangle_count;
|
2011-10-12 08:47:26 +00:00
|
|
|
my $expected_size =
|
|
|
|
+ 80 # header
|
|
|
|
+ 4 # count
|
|
|
|
+ $triangle_count * (
|
|
|
|
+ 4 # normal, pt,pt,pt (vectors)
|
|
|
|
* 4 # bytes per value
|
|
|
|
* 3 # values per vector
|
|
|
|
+ 2 # the trailing 'short'
|
|
|
|
);
|
|
|
|
$mode = ($size == $expected_size) ? 'binary' : 'ascii';
|
|
|
|
}
|
|
|
|
|
2012-02-17 12:49:33 +00:00
|
|
|
my $facets = [];
|
2013-05-14 11:52:29 +00:00
|
|
|
my $vertices = [];
|
2011-10-12 08:47:26 +00:00
|
|
|
$mode eq 'ascii'
|
2013-05-14 11:52:29 +00:00
|
|
|
? _read_ascii($fh, $facets, $vertices)
|
|
|
|
: _read_binary($fh, $facets, $vertices);
|
2011-10-12 08:47:26 +00:00
|
|
|
close $fh;
|
2012-02-17 12:49:33 +00:00
|
|
|
|
2012-08-29 14:49:38 +00:00
|
|
|
my $model = Slic3r::Model->new;
|
|
|
|
my $object = $model->add_object(vertices => $vertices);
|
|
|
|
my $volume = $object->add_volume(facets => $facets);
|
|
|
|
return $model;
|
2011-10-12 08:47:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sub _read_ascii {
|
2013-05-14 11:52:29 +00:00
|
|
|
my ($fh, $facets, $vertices) = @_;
|
2011-10-12 08:47:26 +00:00
|
|
|
|
2013-05-14 12:17:46 +00:00
|
|
|
my $point_re = qr/(([^ ]+)\s+([^ ]+)\s+([^ ]+))/;
|
2011-10-12 08:47:26 +00:00
|
|
|
|
|
|
|
my $facet;
|
2013-05-14 11:52:29 +00:00
|
|
|
my %vertices_map = ();
|
2011-10-12 08:47:26 +00:00
|
|
|
seek $fh, 0, 0;
|
2013-06-06 08:46:58 +00:00
|
|
|
while (<$fh>) {
|
2011-10-12 08:47:26 +00:00
|
|
|
if (!$facet) {
|
2013-06-22 14:15:07 +00:00
|
|
|
/^\s*facet/ or next; # be tolerant with malformed STL files not having the "normal" word
|
2013-05-14 12:12:32 +00:00
|
|
|
$facet = []; # ignore normal
|
2011-10-12 08:47:26 +00:00
|
|
|
} else {
|
|
|
|
if (/^\s*endfacet/) {
|
|
|
|
push @$facets, $facet;
|
|
|
|
undef $facet;
|
|
|
|
} else {
|
2012-04-30 19:49:44 +00:00
|
|
|
/^\s*vertex\s+$point_re/o or next;
|
2013-05-14 12:17:46 +00:00
|
|
|
my $vertex_id = $1;
|
2013-05-14 11:52:29 +00:00
|
|
|
my $vertex_idx;
|
|
|
|
if (exists $vertices_map{$vertex_id}) {
|
|
|
|
$vertex_idx = $vertices_map{$vertex_id};
|
|
|
|
} else {
|
2013-05-14 12:17:46 +00:00
|
|
|
push @$vertices, [map $_ * 1, $2, $3, $4];
|
2013-05-14 11:52:29 +00:00
|
|
|
$vertex_idx = $vertices_map{$vertex_id} = $#$vertices;
|
|
|
|
}
|
|
|
|
push @$facet, $vertex_idx;
|
2011-10-12 08:47:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-10-12 12:54:49 +00:00
|
|
|
if ($facet) {
|
|
|
|
die "STL file seems invalid\n";
|
|
|
|
}
|
2011-10-12 08:47:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sub _read_binary {
|
2013-05-14 11:52:29 +00:00
|
|
|
my ($fh, $facets, $vertices) = @_;
|
2011-10-12 08:47:26 +00:00
|
|
|
|
|
|
|
die "bigfloat" unless length(pack "f", 1) == 4;
|
|
|
|
|
2013-05-14 11:52:29 +00:00
|
|
|
my %vertices_map = ();
|
2011-11-12 10:57:22 +00:00
|
|
|
binmode $fh;
|
2011-10-12 08:47:26 +00:00
|
|
|
seek $fh, 80 + 4, 0;
|
2013-06-06 08:46:58 +00:00
|
|
|
while (read $fh, $_, 4*4*3+2) {
|
2013-05-14 11:52:29 +00:00
|
|
|
push @$facets, my $facet = [];
|
|
|
|
for (unpack 'x[f3](a[f3])3') { # ignore normal
|
|
|
|
my $vertex_idx;
|
|
|
|
if (exists $vertices_map{$_}) {
|
|
|
|
$vertex_idx = $vertices_map{$_};
|
|
|
|
} else {
|
|
|
|
push @$vertices, [ unpack 'f<3', $_ ];
|
|
|
|
$vertex_idx = $vertices_map{$_} = $#$vertices;
|
|
|
|
}
|
|
|
|
push @$facet, $vertex_idx;
|
|
|
|
}
|
2011-10-12 08:47:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-28 14:05:42 +00:00
|
|
|
sub write_file {
|
|
|
|
my $self = shift;
|
2012-08-29 14:49:38 +00:00
|
|
|
my ($file, $model, %params) = @_;
|
2012-01-28 14:05:42 +00:00
|
|
|
|
2013-01-13 09:18:34 +00:00
|
|
|
Slic3r::open(\my $fh, '>', $file);
|
2012-01-28 14:05:42 +00:00
|
|
|
|
2012-08-29 14:49:38 +00:00
|
|
|
$params{binary}
|
|
|
|
? _write_binary($fh, $model->mesh)
|
|
|
|
: _write_ascii($fh, $model->mesh);
|
2012-01-28 14:05:42 +00:00
|
|
|
|
|
|
|
close $fh;
|
|
|
|
}
|
|
|
|
|
|
|
|
sub _write_binary {
|
2012-02-18 19:36:14 +00:00
|
|
|
my ($fh, $mesh) = @_;
|
2012-01-28 14:05:42 +00:00
|
|
|
|
|
|
|
die "bigfloat" unless length(pack "f", 1) == 4;
|
|
|
|
|
|
|
|
binmode $fh;
|
|
|
|
print $fh pack 'x80';
|
2012-02-18 19:36:14 +00:00
|
|
|
print $fh pack 'L', scalar(@{$mesh->facets});
|
|
|
|
foreach my $facet (@{$mesh->facets}) {
|
2012-02-19 14:45:27 +00:00
|
|
|
print $fh pack '(f<3)4S',
|
|
|
|
@{_facet_normal($mesh, $facet)},
|
2012-07-30 07:59:41 +00:00
|
|
|
(map @{$mesh->vertices->[$_]}, @$facet[-3..-1]),
|
2012-02-19 14:45:27 +00:00
|
|
|
0;
|
2012-02-18 19:36:14 +00:00
|
|
|
}
|
2012-01-28 14:05:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sub _write_ascii {
|
2012-02-18 19:36:14 +00:00
|
|
|
my ($fh, $mesh) = @_;
|
2012-01-28 14:05:42 +00:00
|
|
|
|
|
|
|
printf $fh "solid\n";
|
2012-02-18 19:36:14 +00:00
|
|
|
foreach my $facet (@{$mesh->facets}) {
|
2012-02-19 14:45:27 +00:00
|
|
|
printf $fh " facet normal %f %f %f\n", @{_facet_normal($mesh, $facet)};
|
2012-01-28 14:05:42 +00:00
|
|
|
printf $fh " outer loop\n";
|
2012-07-30 07:59:41 +00:00
|
|
|
printf $fh " vertex %f %f %f\n", @{$mesh->vertices->[$_]} for @$facet[-3..-1];
|
2012-01-28 14:05:42 +00:00
|
|
|
printf $fh " endloop\n";
|
|
|
|
printf $fh " endfacet\n";
|
|
|
|
}
|
|
|
|
printf $fh "endsolid\n";
|
|
|
|
}
|
|
|
|
|
2012-02-19 14:45:27 +00:00
|
|
|
sub _facet_normal {
|
|
|
|
my ($mesh, $facet) = @_;
|
2012-07-30 07:59:41 +00:00
|
|
|
return triangle_normal(map $mesh->vertices->[$_], @$facet[-3..-1]);
|
2012-02-19 14:45:27 +00:00
|
|
|
}
|
|
|
|
|
2011-09-01 19:06:28 +00:00
|
|
|
1;
|