Refactoring: moved Slic3r::STL and Slic3r::AMF to Slic3r::Format::*
This commit is contained in:
parent
2a86932cfe
commit
959230b099
9 changed files with 18 additions and 18 deletions
210
lib/Slic3r/Format/STL.pm
Normal file
210
lib/Slic3r/Format/STL.pm
Normal file
|
@ -0,0 +1,210 @@
|
|||
package Slic3r::Format::STL;
|
||||
use Moo;
|
||||
|
||||
use Slic3r::Geometry qw(X Y Z triangle_normal);
|
||||
use XXX;
|
||||
|
||||
sub read_file {
|
||||
my $self = shift;
|
||||
my ($file) = @_;
|
||||
|
||||
open my $fh, '<', $file or die "Failed to open $file\n";
|
||||
|
||||
# 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;
|
||||
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 = [];
|
||||
$mode eq 'ascii'
|
||||
? _read_ascii($fh, $facets)
|
||||
: _read_binary($fh, $facets);
|
||||
close $fh;
|
||||
|
||||
my $vertices = [];
|
||||
{
|
||||
my %vertices_map = (); # given a vertex's coordinates, what's its index?
|
||||
my @vertices_facets = (); # given a vertex index, what are the indexes of its tangent facets?
|
||||
for (my $f = 0; $f <= $#$facets; $f++) {
|
||||
for (1..3) {
|
||||
my $point_id = join ',', @{$facets->[$f][$_]};
|
||||
if (exists $vertices_map{$point_id}) {
|
||||
$facets->[$f][$_] = $vertices_map{$point_id};
|
||||
push @{$vertices_facets[$facets->[$f][$_]]}, $f;
|
||||
} else {
|
||||
push @$vertices, $facets->[$f][$_];
|
||||
$facets->[$f][$_] = $vertices_map{$point_id} = $#$vertices;
|
||||
$vertices_facets[$#$vertices] = [$f];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# The following loop checks that @vertices_facets only groups facets that
|
||||
# are really connected together (i.e. neighbors or sharing neighbors);
|
||||
# in other words it takes care of multiple vertices occupying the same
|
||||
# point in space. It enforces topological correctness which is needed by
|
||||
# the slicing algorithm.
|
||||
# I'm keeping it disabled until I find a good test case.
|
||||
if (0) {
|
||||
my $vertices_count = $#$vertices; # store it to avoid processing newly created vertices
|
||||
for (my $v = 0; $v <= $vertices_count; $v++) {
|
||||
my $more_than_one_vertex_in_this_point = 0;
|
||||
while (@{$vertices_facets[$v]}) {
|
||||
my @facets_indexes = @{$vertices_facets[$v]};
|
||||
@{$vertices_facets[$v]} = ();
|
||||
|
||||
my @this_f = shift @facets_indexes;
|
||||
CYCLE: while (@facets_indexes && @this_f) {
|
||||
|
||||
# look for a facet that is connected to $this_f[-1] and whose common line contains $v
|
||||
my @other_vertices_indexes = grep $_ != $v, @{$facets->[$this_f[-1]]}[1..3];
|
||||
|
||||
OTHER: for my $other_f (@facets_indexes) {
|
||||
# facet is connected if it shares one more point
|
||||
for (grep $_ != $v, @{$facets->[$other_f]}[1..3]) {
|
||||
if ($_ ~~ @other_vertices_indexes) {
|
||||
#printf "facet %d is connected to $other_f (sharing vertices $v and $_)\n", $this_f[-1];
|
||||
|
||||
# TODO: we should ensure that the common edge has a different orientation
|
||||
# for each of the two adjacent facets
|
||||
|
||||
push @this_f, $other_f;
|
||||
@facets_indexes = grep $_ != $other_f, @facets_indexes;
|
||||
next CYCLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
# if we're here, then we couldn't find any facet connected to $this_f[-1]
|
||||
# so we should move this one to a different cluster (that is, a new vertex)
|
||||
# (or ignore it if it turns to be a non-manifold facet)
|
||||
if (@this_f > 1) {
|
||||
push @{$vertices_facets[$v]}, $this_f[-1];
|
||||
pop @this_f;
|
||||
$more_than_one_vertex_in_this_point++;
|
||||
} else {
|
||||
last CYCLE;
|
||||
}
|
||||
}
|
||||
|
||||
if ($more_than_one_vertex_in_this_point) {
|
||||
Slic3r::debugf " more than one vertex in the same point\n";
|
||||
push @$vertices, $vertices->[$v];
|
||||
for my $f (@this_f) {
|
||||
$facets->[$f][$_] = $#$vertices for grep $facets->[$f][$_] == $v, 1..3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Slic3r::TriangleMesh->new(vertices => $vertices, facets => $facets);
|
||||
}
|
||||
|
||||
sub _read_ascii {
|
||||
my ($fh, $facets) = @_;
|
||||
|
||||
my $point_re = qr/([^ ]+)\s+([^ ]+)\s+([^ ]+)\s*$/;
|
||||
|
||||
my $facet;
|
||||
seek $fh, 0, 0;
|
||||
while (my $_ = <$fh>) {
|
||||
s/\R+$//;
|
||||
if (!$facet) {
|
||||
/^\s*facet\s+normal\s+$point_re/ or next;
|
||||
$facet = [ [$1, $2, $3] ];
|
||||
} else {
|
||||
if (/^\s*endfacet/) {
|
||||
push @$facets, $facet;
|
||||
undef $facet;
|
||||
} else {
|
||||
/^\s*vertex\s+$point_re/ or next;
|
||||
push @$facet, [map $_ * 1, $1, $2, $3];
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($facet) {
|
||||
die "STL file seems invalid\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub _read_binary {
|
||||
my ($fh, $facets) = @_;
|
||||
|
||||
die "bigfloat" unless length(pack "f", 1) == 4;
|
||||
|
||||
binmode $fh;
|
||||
seek $fh, 80 + 4, 0;
|
||||
while (read $fh, my $_, 4*4*3+2) {
|
||||
my @v = unpack '(f<3)4';
|
||||
push @$facets, [ [@v[0..2]], [@v[3..5]], [@v[6..8]], [@v[9..11]] ];
|
||||
}
|
||||
}
|
||||
|
||||
sub write_file {
|
||||
my $self = shift;
|
||||
my ($file, $mesh, $binary) = @_;
|
||||
|
||||
open my $fh, '>', $file;
|
||||
|
||||
$binary
|
||||
? _write_binary($fh, $mesh)
|
||||
: _write_ascii($fh, $mesh);
|
||||
|
||||
close $fh;
|
||||
}
|
||||
|
||||
sub _write_binary {
|
||||
my ($fh, $mesh) = @_;
|
||||
|
||||
die "bigfloat" unless length(pack "f", 1) == 4;
|
||||
|
||||
binmode $fh;
|
||||
print $fh pack 'x80';
|
||||
print $fh pack 'L', scalar(@{$mesh->facets});
|
||||
foreach my $facet (@{$mesh->facets}) {
|
||||
print $fh pack '(f<3)4S',
|
||||
@{_facet_normal($mesh, $facet)},
|
||||
(map @{$mesh->vertices->[$_]}, @$facet[1,2,3]),
|
||||
0;
|
||||
}
|
||||
}
|
||||
|
||||
sub _write_ascii {
|
||||
my ($fh, $mesh) = @_;
|
||||
|
||||
printf $fh "solid\n";
|
||||
foreach my $facet (@{$mesh->facets}) {
|
||||
printf $fh " facet normal %f %f %f\n", @{_facet_normal($mesh, $facet)};
|
||||
printf $fh " outer loop\n";
|
||||
printf $fh " vertex %f %f %f\n", @{$mesh->vertices->[$_]} for @$facet[1,2,3];
|
||||
printf $fh " endloop\n";
|
||||
printf $fh " endfacet\n";
|
||||
}
|
||||
printf $fh "endsolid\n";
|
||||
}
|
||||
|
||||
sub _facet_normal {
|
||||
my ($mesh, $facet) = @_;
|
||||
return triangle_normal(map $mesh->vertices->[$_], @$facet[1,2,3]);
|
||||
}
|
||||
|
||||
1;
|
Loading…
Add table
Add a link
Reference in a new issue