diff --git a/lib/Slic3r/Geometry/BoundingBox.pm b/lib/Slic3r/Geometry/BoundingBox.pm index a05039c7c..0236cd33f 100644 --- a/lib/Slic3r/Geometry/BoundingBox.pm +++ b/lib/Slic3r/Geometry/BoundingBox.pm @@ -165,4 +165,14 @@ sub y_max { return $self->extents->[Y][MAX]; } +sub z_min { + my $self = shift; + return $self->extents->[Z][MIN]; +} + +sub z_max { + my $self = shift; + return $self->extents->[Z][MAX]; +} + 1; diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index 8fb1c667e..e8e8c9893 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -84,8 +84,11 @@ sub add_model_object { my %matmap = %{ $object->material_mapping || {} }; $_-- for values %matmap; # extruders in the mapping are 1-indexed but we want 0-indexed - my %meshes = (); # region_id => TriangleMesh - foreach my $volume (@{$object->volumes}) { + my %volumes = (); # region_id => [ volume_id, ... ] + foreach my $volume_id (0..$#{$object->volumes}) { + my $volume = $object->volumes->[$volume_id]; + + # determine what region should this volume be mapped to my $region_id; if (defined $volume->material_id) { if (!exists $matmap{ $volume->material_id }) { @@ -96,27 +99,19 @@ sub add_model_object { } else { $region_id = 0; } + $volumes{$region_id} //= []; + push @{ $volumes{$region_id} }, $volume_id; # instantiate region if it does not exist $self->regions->[$region_id] //= Slic3r::Print::Region->new; - - # if a mesh is already associated to this region, append this one to it - $meshes{$region_id} //= Slic3r::TriangleMesh->new; - $meshes{$region_id}->merge($volume->mesh); - } - - foreach my $mesh (values %meshes) { - # we ignore the per-instance transformations currently and only - # consider the first one - $object->instances->[0]->transform_mesh($mesh, 1); } # initialize print object my $o = Slic3r::Print::Object->new( print => $self, - meshes => [ map $meshes{$_}, 0..$#{$self->regions} ], + model_object => $object, + region_volumes => [ map $volumes{$_}, 0..$#{$self->regions} ], copies => [ map Slic3r::Point->new_scale(@{ $_->offset }), @{ $object->instances } ], - input_file => $object->input_file, config_overrides => $object->config, layer_height_ranges => $object->layer_height_ranges, ); @@ -892,7 +887,7 @@ sub expanded_output_filepath { @$extra_variables{qw(input_filename input_filename_base)} = parse_filename($input_file); } else { # if no input file was supplied, take the first one from our objects - $input_file = $self->objects->[0]->input_file // return undef; + $input_file = $self->objects->[0]->model_object->input_file // return undef; } if ($path && -d $path) { diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index 333f87593..a136ff467 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -8,8 +8,8 @@ use Slic3r::Geometry::Clipper qw(diff diff_ex intersection intersection_ex union use Slic3r::Surface ':types'; has 'print' => (is => 'ro', weak_ref => 1, required => 1); -has 'input_file' => (is => 'rw', required => 0); -has 'meshes' => (is => 'rw', default => sub { [] }); # by region_id +has 'model_object' => (is => 'ro', required => 1); +has 'region_volumes' => (is => 'rw', default => sub { [] }); # by region_id has 'copies' => (is => 'ro'); # Slic3r::Point objects in scaled G-code coordinates has 'config_overrides' => (is => 'rw', default => sub { Slic3r::Config->new }); has 'config' => (is => 'rw'); @@ -30,15 +30,16 @@ sub BUILD { # translate meshes so that we work with smaller coordinates { # compute the bounding box of the supplied meshes - my @meshes = grep defined $_, @{$self->meshes}; # in no particular order + my @meshes = map $self->model_object->volumes->[$_]->mesh, + map @$_, + grep defined $_, + @{$self->region_volumes}; my $bb = Slic3r::Geometry::BoundingBox->merge(map $_->bounding_box, @meshes); # Translate meshes so that our toolpath generation algorithms work with smaller # XY coordinates; this translation is an optimization and not strictly required. # However, this also aligns object to Z = 0, which on the contrary is required # since we don't assume input is already aligned. - $_->translate(@{$bb->vector_to_origin}) for @meshes; - # We store the XY translation so that we can place copies correctly in the output G-code # (copies are expressed in G-code coordinates and this translation is not publicly exposed). $self->_copies_shift(Slic3r::Point->new_scale($bb->x_min, $bb->y_min)); @@ -167,8 +168,26 @@ sub slice { } # process facets - for my $region_id (0 .. $#{$self->meshes}) { - my $mesh = $self->meshes->[$region_id] // next; # ignore undef meshes + for my $region_id (0..$#{$self->region_volumes}) { + next if !defined $self->region_volumes->[$region_id]; + + # compose mesh + my $mesh; + foreach my $volume_id (@{$self->region_volumes->[$region_id]}) { + if (defined $mesh) { + $mesh->merge($self->model_object->volumes->[$volume_id]->mesh); + } else { + $mesh = $self->model_object->volumes->[$volume_id]->mesh->clone; + } + } + + # transform mesh + # we ignore the per-instance transformations currently and only + # consider the first one + $self->model_object->instances->[0]->transform_mesh($mesh, 1); + + # align mesh to Z = 0 and apply XY shift + $mesh->translate((map unscale(-$_), @{$self->_copies_shift}), -$mesh->bounding_box->z_min); { my $loops = $mesh->slice([ map $_->slice_z, @{$self->layers} ]); @@ -178,15 +197,8 @@ sub slice { } # TODO: read slicing_errors } - - # free memory - undef $mesh; - undef $self->meshes->[$region_id]; } - # free memory - $self->meshes(undef); - # remove last layer(s) if empty pop @{$self->layers} while @{$self->layers} && (!map @{$_->slices}, @{$self->layers->[-1]->regions});