diff --git a/lib/Slic3r/Format/STL.pm b/lib/Slic3r/Format/STL.pm index 2d537c126..ed7984f4c 100644 --- a/lib/Slic3r/Format/STL.pm +++ b/lib/Slic3r/Format/STL.pm @@ -1,20 +1,17 @@ package Slic3r::Format::STL; use Moo; -use Slic3r::Geometry qw(X Y Z triangle_normal); - sub read_file { my $self = shift; my ($file) = @_; - my $tmesh = Slic3r::TriangleMesh->new; - $tmesh->ReadSTLFile(Slic3r::encode_path($file)); - $tmesh->repair; - my ($vertices, $facets) = ($tmesh->vertices, $tmesh->facets); + my $mesh = Slic3r::TriangleMesh->new; + $mesh->ReadSTLFile(Slic3r::encode_path($file)); + $mesh->repair; my $model = Slic3r::Model->new; - my $object = $model->add_object(vertices => $vertices, mesh_stats => $tmesh->stats); - my $volume = $object->add_volume(facets => $facets); + my $object = $model->add_object; + my $volume = $object->add_volume(mesh => $mesh); return $model; } @@ -22,48 +19,11 @@ sub write_file { my $self = shift; my ($file, $model, %params) = @_; - Slic3r::open(\my $fh, '>', $file); + my $path = Slic3r::encode_path($file); $params{binary} - ? _write_binary($fh, $model->mesh) - : _write_ascii($fh, $model->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[-3..-1]), - 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[-3..-1]; - 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[-3..-1]); + ? $model->mesh->write_binary($path) + : $model->mesh->write_ascii($path); } 1; diff --git a/lib/Slic3r/Model.pm b/lib/Slic3r/Model.pm index 9667e6db2..2052df8b1 100644 --- a/lib/Slic3r/Model.pm +++ b/lib/Slic3r/Model.pm @@ -315,32 +315,21 @@ use Storable qw(dclone); has 'input_file' => (is => 'rw'); has 'model' => (is => 'ro', weak_ref => 1, required => 1); -has 'vertices' => (is => 'ro', default => sub { [] }); has 'volumes' => (is => 'ro', default => sub { [] }); has 'instances' => (is => 'rw'); has 'config' => (is => 'rw', default => sub { Slic3r::Config->new }); has 'layer_height_ranges' => (is => 'rw', default => sub { [] }); # [ z_min, z_max, layer_height ] has 'material_mapping' => (is => 'rw', default => sub { {} }); # { material_id => extruder_idx } -has 'mesh_stats' => (is => 'rw'); has '_bounding_box' => (is => 'rw'); sub add_volume { my $self = shift; my %args = @_; - if (my $vertices = delete $args{vertices}) { - my $v_offset = @{$self->vertices}; - push @{$self->vertices}, @$vertices; - - @{$args{facets}} = map { - my $f = [@$_]; - $f->[$_] += $v_offset for -3..-1; - $f; - } @{$args{facets}}; - } - - my $volume = Slic3r::Model::Volume->new(object => $self, %args); - push @{$self->volumes}, $volume; + push @{$self->volumes}, my $volume = Slic3r::Model::Volume->new( + object => $self, + %args, + ); $self->_bounding_box(undef); $self->model->_bounding_box(undef); return $volume; @@ -358,16 +347,14 @@ sub add_instance { sub mesh { my $self = shift; - # this mesh won't be suitable for check_manifoldness as multiple - # facets from different volumes may use the same vertices my $mesh = Slic3r::TriangleMesh->new; - $mesh->ReadFromPerl($self->vertices, [ map @{$_->facets}, @{$self->volumes} ]); + $mesh->merge($_->mesh) for @{$self->volumes}; return $mesh; } sub used_vertices { my $self = shift; - return [ map $self->vertices->[$_], map @$_, map @{$_->facets}, @{$self->volumes} ]; + return [ map $_->mesh->used_vertices, @{$self->volumes} ]; } sub size { @@ -389,7 +376,8 @@ sub bounding_box { my $self = shift; if (!defined $self->_bounding_box) { - $self->_bounding_box(Slic3r::Geometry::BoundingBox->new_from_points_3D($self->used_vertices)); + # TODO: calculate bb in XS + $self->_bounding_box(Slic3r::Geometry::BoundingBox->new_from_points_3D(map $_->mesh->vertices, @{$self->volumes})); } return $self->_bounding_box; } @@ -409,7 +397,7 @@ sub move { my $self = shift; my @shift = @_; - @{$self->vertices} = move_points_3D([ @shift ], @{$self->vertices}); + $_->mesh->translate(@shift) for @{$self->volumes}; $self->_bounding_box->translate(@shift) if defined $self->_bounding_box; } @@ -418,13 +406,8 @@ sub scale { my ($factor) = @_; return if $factor == 1; - # transform vertex coordinates - foreach my $vertex (@{$self->vertices}) { - $vertex->[$_] *= $factor for X,Y,Z; - } - + $_->mesh->scale($factor) for @{$self->volumes}; $self->_bounding_box->scale($factor) if defined $self->_bounding_box; - $self->mesh_stats->{volume} *= ($factor**3) if defined $self->mesh_stats; } sub rotate { @@ -432,13 +415,7 @@ sub rotate { my ($deg) = @_; return if $deg == 0; - my $rad = Slic3r::Geometry::deg2rad($deg); - - # transform vertex coordinates - foreach my $vertex (@{$self->vertices}) { - @$vertex = (@{ +(Slic3r::Geometry::rotate_points($rad, undef, [ $vertex->[X], $vertex->[Y] ]))[0] }, $vertex->[Z]); - } - + $_->mesh->rotate($deg, Slic3r::Point->(0,0)) for @{$self->volumes}; $self->_bounding_box(undef); } @@ -499,20 +476,7 @@ use Moo; has 'object' => (is => 'ro', weak_ref => 1, required => 1); has 'material_id' => (is => 'rw'); -has 'facets' => (is => 'rw', default => sub { [] }); - -sub mesh { - my $self = shift; - - my $mesh = Slic3r::TriangleMesh->new; - $mesh->ReadFromPerl($self->object->vertices, $self->facets); - return $mesh; -} - -sub facets_count { - my $self = shift; - return scalar(@{$self->facets}); # TODO: optimize in XS -} +has 'mesh' => (is => 'rw', required => 1); package Slic3r::Model::Instance; use Moo; diff --git a/lib/Slic3r/TriangleMesh.pm b/lib/Slic3r/TriangleMesh.pm index 7831e5057..434b5ada2 100644 --- a/lib/Slic3r/TriangleMesh.pm +++ b/lib/Slic3r/TriangleMesh.pm @@ -24,6 +24,11 @@ sub used_vertices { return $self->vertices; } +sub facets_count { + my $self = shift; + return $self->stats->{number_of_facets}; +} + sub bounding_box { my $self = shift; return Slic3r::Geometry::BoundingBox->new_from_points_3D($self->used_vertices); diff --git a/xs/src/TriangleMesh.cpp b/xs/src/TriangleMesh.cpp index 8f6ac0b10..81cebb7d8 100644 --- a/xs/src/TriangleMesh.cpp +++ b/xs/src/TriangleMesh.cpp @@ -50,6 +50,18 @@ TriangleMesh::ReadSTLFile(char* input_file) { stl_open(&stl, input_file); } +void +TriangleMesh::write_ascii(char* output_file) +{ + stl_write_ascii(&this->stl, output_file, ""); +} + +void +TriangleMesh::write_binary(char* output_file) +{ + stl_write_binary(&this->stl, output_file, ""); +} + void TriangleMesh::ReadFromPerl(SV* vertices, SV* facets) { stl_initialize(&stl); diff --git a/xs/src/TriangleMesh.hpp b/xs/src/TriangleMesh.hpp index b47f368ed..30729bf63 100644 --- a/xs/src/TriangleMesh.hpp +++ b/xs/src/TriangleMesh.hpp @@ -20,6 +20,8 @@ class TriangleMesh ~TriangleMesh(); SV* to_SV(); void ReadSTLFile(char* input_file); + void write_ascii(char* output_file); + void write_binary(char* output_file); void ReadFromPerl(SV* vertices, SV* facets); void repair(); void WriteOBJFile(char* output_file); diff --git a/xs/src/admesh/stl.h b/xs/src/admesh/stl.h index 04aa8220d..699044866 100644 --- a/xs/src/admesh/stl.h +++ b/xs/src/admesh/stl.h @@ -139,8 +139,8 @@ extern void stl_close(stl_file *stl); extern void stl_stats_out(stl_file *stl, FILE *file, char *input_file); extern void stl_print_edges(stl_file *stl, FILE *file); extern void stl_print_neighbors(stl_file *stl, char *file); -extern void stl_write_ascii(stl_file *stl, char *file, char *label); -extern void stl_write_binary(stl_file *stl, char *file, char *label); +extern void stl_write_ascii(stl_file *stl, const char *file, const char *label); +extern void stl_write_binary(stl_file *stl, const char *file, const char *label); extern void stl_check_facets_exact(stl_file *stl); extern void stl_check_facets_nearby(stl_file *stl, float tolerance); extern void stl_remove_unconnected_facets(stl_file *stl); diff --git a/xs/src/admesh/stl_io.c b/xs/src/admesh/stl_io.c index 1b2671ab2..daa999b8d 100644 --- a/xs/src/admesh/stl_io.c +++ b/xs/src/admesh/stl_io.c @@ -121,7 +121,7 @@ Normals fixed : %5d\n", stl->stats.normals_fixed); } void -stl_write_ascii(stl_file *stl, char *file, char *label) +stl_write_ascii(stl_file *stl, const char *file, const char *label) { int i; FILE *fp; @@ -241,7 +241,7 @@ stl_put_little_float(FILE *fp, float value_in) void -stl_write_binary(stl_file *stl, char *file, char *label) +stl_write_binary(stl_file *stl, const char *file, const char *label) { FILE *fp; int i; diff --git a/xs/xsp/TriangleMesh.xsp b/xs/xsp/TriangleMesh.xsp index a41f3b098..df0b827b5 100644 --- a/xs/xsp/TriangleMesh.xsp +++ b/xs/xsp/TriangleMesh.xsp @@ -11,6 +11,8 @@ TriangleMesh* clone() %code{% const char* CLASS = "Slic3r::TriangleMesh"; RETVAL = new TriangleMesh(*THIS); %}; void ReadSTLFile(char* input_file); + void write_ascii(char* output_file); + void write_binary(char* output_file); void ReadFromPerl(SV* vertices, SV* facets); void repair(); void WriteOBJFile(char* output_file);