Automatically repair any input STL file
This commit is contained in:
parent
d30b4f0310
commit
5975145426
@ -7,37 +7,10 @@ sub read_file {
|
|||||||
my $self = shift;
|
my $self = shift;
|
||||||
my ($file) = @_;
|
my ($file) = @_;
|
||||||
|
|
||||||
Slic3r::open(\my $fh, '<', $file) or die "Failed to open $file\n";
|
my $tmesh = Slic3r::TriangleMesh::XS->new;
|
||||||
|
$tmesh->ReadSTLFile($file);
|
||||||
# let's detect whether file is ASCII or binary
|
$tmesh->Repair;
|
||||||
my $mode;
|
my ($vertices, $facets) = @{$tmesh->ToPerl};
|
||||||
{
|
|
||||||
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;
|
|
||||||
die "STL file seems invalid, could not read facet count\n" if !defined $triangle_count;
|
|
||||||
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';
|
|
||||||
}
|
|
||||||
|
|
||||||
my $facets = [];
|
|
||||||
my $vertices = [];
|
|
||||||
$mode eq 'ascii'
|
|
||||||
? _read_ascii($fh, $facets, $vertices)
|
|
||||||
: _read_binary($fh, $facets, $vertices);
|
|
||||||
close $fh;
|
|
||||||
|
|
||||||
my $model = Slic3r::Model->new;
|
my $model = Slic3r::Model->new;
|
||||||
my $object = $model->add_object(vertices => $vertices);
|
my $object = $model->add_object(vertices => $vertices);
|
||||||
@ -45,64 +18,6 @@ sub read_file {
|
|||||||
return $model;
|
return $model;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub _read_ascii {
|
|
||||||
my ($fh, $facets, $vertices) = @_;
|
|
||||||
|
|
||||||
my $point_re = qr/(([^ ]+)\s+([^ ]+)\s+([^ ]+))/;
|
|
||||||
|
|
||||||
my $facet;
|
|
||||||
my %vertices_map = ();
|
|
||||||
seek $fh, 0, 0;
|
|
||||||
while (<$fh>) {
|
|
||||||
if (!$facet) {
|
|
||||||
/^\s*facet/ or next; # be tolerant with malformed STL files not having the "normal" word
|
|
||||||
$facet = []; # ignore normal
|
|
||||||
} else {
|
|
||||||
if (/^\s*endfacet/) {
|
|
||||||
push @$facets, $facet;
|
|
||||||
undef $facet;
|
|
||||||
} else {
|
|
||||||
/^\s*vertex\s+$point_re/o or next;
|
|
||||||
my $vertex_id = $1;
|
|
||||||
my $vertex_idx;
|
|
||||||
if (exists $vertices_map{$vertex_id}) {
|
|
||||||
$vertex_idx = $vertices_map{$vertex_id};
|
|
||||||
} else {
|
|
||||||
push @$vertices, [map $_ * 1, $2, $3, $4];
|
|
||||||
$vertex_idx = $vertices_map{$vertex_id} = $#$vertices;
|
|
||||||
}
|
|
||||||
push @$facet, $vertex_idx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($facet) {
|
|
||||||
die "STL file seems invalid\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub _read_binary {
|
|
||||||
my ($fh, $facets, $vertices) = @_;
|
|
||||||
|
|
||||||
die "bigfloat" unless length(pack "f", 1) == 4;
|
|
||||||
|
|
||||||
my %vertices_map = ();
|
|
||||||
binmode $fh;
|
|
||||||
seek $fh, 80 + 4, 0;
|
|
||||||
while (read $fh, $_, 4*4*3+2) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub write_file {
|
sub write_file {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my ($file, $model, %params) = @_;
|
my ($file, $model, %params) = @_;
|
||||||
|
@ -9,8 +9,4 @@ use Test::More tests => 1;
|
|||||||
is Slic3r::TriangleMesh::XS::hello_world(), 'Hello world!',
|
is Slic3r::TriangleMesh::XS::hello_world(), 'Hello world!',
|
||||||
'hello world';
|
'hello world';
|
||||||
|
|
||||||
my $t = Slic3r::TriangleMesh::XS->new();
|
|
||||||
$t->ReadSTLFile("../../stl/testcube20mm.stl");
|
|
||||||
use XXX; XXX($t);
|
|
||||||
|
|
||||||
__END__
|
__END__
|
||||||
|
Loading…
Reference in New Issue
Block a user