diff --git a/lib/Slic3r/Format/AMF/Parser.pm b/lib/Slic3r/Format/AMF/Parser.pm index f6713f5c7..ade2c44ac 100644 --- a/lib/Slic3r/Format/AMF/Parser.pm +++ b/lib/Slic3r/Format/AMF/Parser.pm @@ -143,6 +143,7 @@ sub end_document { } foreach my $instance (@{ $self->{_instances}{$object_id} }) { + next if !defined($instance->{deltax}) || !defined($instance->{deltay}); $self->{_model}->objects->[$new_object_id]->add_instance( rotation => $instance->{rz} || 0, offset => Slic3r::Pointf->new($instance->{deltax} || 0, $instance->{deltay} || 0), diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index 09d15886d..5758ea83a 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -523,6 +523,16 @@ sub load_file { Slic3r::GUI::show_error($self, $@) if $@; if (defined $model) { + if ($model->looks_like_multipart_object) { + my $dialog = Wx::MessageDialog->new($self, + "This file contains several objects positioned at multiple heights. " + . "Instead of considering them as multiple objects, should I consider\n" + . "this file as a single object having multiple parts?\n", + 'Multi-part object detected', wxICON_WARNING | wxYES | wxNO); + if ($dialog->ShowModal() == wxID_YES) { + $model->convert_multipart_object; + } + } $self->load_model_objects(@{$model->objects}); $self->statusbar->SetStatusText("Loaded " . basename($input_file)); } diff --git a/lib/Slic3r/Model.pm b/lib/Slic3r/Model.pm index 9edcae501..057c1f7fe 100644 --- a/lib/Slic3r/Model.pm +++ b/lib/Slic3r/Model.pm @@ -1,6 +1,6 @@ package Slic3r::Model; -use List::Util qw(first max); +use List::Util qw(first max any); use Slic3r::Geometry qw(X Y Z move_points); sub read_from_file { @@ -72,6 +72,33 @@ sub print_info { $_->print_info for @{$self->objects}; } +sub looks_like_multipart_object { + my ($self) = @_; + + return 0 if $self->objects_count == 1; + return 0 if any { $_->volumes_count > 1 } @{$self->objects}; + return 0 if any { @{$_->config->get_keys} > 1 } @{$self->objects}; + + my %heights = map { $_ => 1 } map $_->mesh->bounding_box->z_min, map @{$_->volumes}, @{$self->objects}; + return scalar(keys %heights) > 1; +} + +sub convert_multipart_object { + my ($self) = @_; + + my @objects = @{$self->objects}; + my $object = $self->add_object( + input_file => $objects[0]->input_file, + ); + foreach my $v (map @{$_->volumes}, @objects) { + my $volume = $object->add_volume($v); + $volume->set_name($v->object->name); + } + $object->add_instance($_) for map @{$_->instances}, @objects; + + $self->delete_object($_) for reverse 0..($self->objects_count-2); +} + package Slic3r::Model::Material; sub apply { diff --git a/xs/src/libslic3r/Model.cpp b/xs/src/libslic3r/Model.cpp index 6a678f4b6..9eaf5e2f7 100644 --- a/xs/src/libslic3r/Model.cpp +++ b/xs/src/libslic3r/Model.cpp @@ -324,7 +324,7 @@ ModelMaterial::apply(const t_model_material_attributes &attributes) ModelObject::ModelObject(Model *model) - : model(model) + : model(model), _bounding_box_valid(false) {} ModelObject::ModelObject(Model *model, const ModelObject &other, bool copy_volumes)