Ability to customize how materials are mapped to extruders. #1020
This commit is contained in:
parent
cb0ee9729f
commit
026e0c06e4
6 changed files with 134 additions and 34 deletions
|
@ -27,14 +27,14 @@ sub start_element {
|
||||||
$self->{_coordinate} = $data->{LocalName};
|
$self->{_coordinate} = $data->{LocalName};
|
||||||
} elsif ($data->{LocalName} eq 'volume') {
|
} elsif ($data->{LocalName} eq 'volume') {
|
||||||
$self->{_volume} = $self->{_object}->add_volume(
|
$self->{_volume} = $self->{_object}->add_volume(
|
||||||
material_id => $self->_get_attribute($data, 'materialid') || undef,
|
material_id => $self->_get_attribute($data, 'materialid') // undef,
|
||||||
);
|
);
|
||||||
} elsif ($data->{LocalName} eq 'triangle') {
|
} elsif ($data->{LocalName} eq 'triangle') {
|
||||||
$self->{_triangle} = ["", "", ""];
|
$self->{_triangle} = ["", "", ""];
|
||||||
} elsif ($self->{_triangle} && $data->{LocalName} =~ /^v([123])$/ && $self->{_tree}[-1] eq 'triangle') {
|
} elsif ($self->{_triangle} && $data->{LocalName} =~ /^v([123])$/ && $self->{_tree}[-1] eq 'triangle') {
|
||||||
$self->{_vertex_idx} = $1-1;
|
$self->{_vertex_idx} = $1-1;
|
||||||
} elsif ($data->{LocalName} eq 'material') {
|
} elsif ($data->{LocalName} eq 'material') {
|
||||||
my $material_id = $self->_get_attribute($data, 'id') || '_';
|
my $material_id = $self->_get_attribute($data, 'id') // '_';
|
||||||
$self->{_material} = $self->{_model}->set_material($material_id);
|
$self->{_material} = $self->{_model}->set_material($material_id);
|
||||||
} elsif ($data->{LocalName} eq 'metadata' && $self->{_tree}[-1] eq 'material') {
|
} elsif ($data->{LocalName} eq 'metadata' && $self->{_tree}[-1] eq 'material') {
|
||||||
$self->{_material_metadata_type} = $self->_get_attribute($data, 'type');
|
$self->{_material_metadata_type} = $self->_get_attribute($data, 'type');
|
||||||
|
|
|
@ -389,8 +389,9 @@ sub load_file {
|
||||||
name => $basename,
|
name => $basename,
|
||||||
input_file => $input_file,
|
input_file => $input_file,
|
||||||
input_file_object_id => $i,
|
input_file_object_id => $i,
|
||||||
model_object => $model->objects->[$i],
|
model => $model,
|
||||||
mesh_stats => $model->objects->[$i]->mesh_stats, # so that we can free model_object
|
model_object_idx => $i,
|
||||||
|
mesh_stats => $model->objects->[$i]->mesh_stats, # so that we can free model
|
||||||
instances => [
|
instances => [
|
||||||
$model->objects->[$i]->instances
|
$model->objects->[$i]->instances
|
||||||
? (map $_->offset, @{$model->objects->[$i]->instances})
|
? (map $_->offset, @{$model->objects->[$i]->instances})
|
||||||
|
@ -589,7 +590,8 @@ sub split_object {
|
||||||
name => basename($current_object->input_file),
|
name => basename($current_object->input_file),
|
||||||
input_file => $current_object->input_file,
|
input_file => $current_object->input_file,
|
||||||
input_file_object_id => undef,
|
input_file_object_id => undef,
|
||||||
model_object => $model_object,
|
model => $new_model,
|
||||||
|
model_object_idx => $#{$new_model->objects},
|
||||||
instances => [ map $bb->min_point, 1..$current_copies_num ],
|
instances => [ map $bb->min_point, 1..$current_copies_num ],
|
||||||
);
|
);
|
||||||
push @{ $self->{objects} }, $object;
|
push @{ $self->{objects} }, $object;
|
||||||
|
@ -629,6 +631,8 @@ sub export_gcode {
|
||||||
|
|
||||||
$self->statusbar->StartBusy;
|
$self->statusbar->StartBusy;
|
||||||
|
|
||||||
|
$_->free_model_object for @{$self->{objects}};
|
||||||
|
|
||||||
# It looks like declaring a local $SIG{__WARN__} prevents the ugly
|
# It looks like declaring a local $SIG{__WARN__} prevents the ugly
|
||||||
# "Attempt to free unreferenced scalar" warning...
|
# "Attempt to free unreferenced scalar" warning...
|
||||||
local $SIG{__WARN__} = Slic3r::GUI::warning_catcher($self);
|
local $SIG{__WARN__} = Slic3r::GUI::warning_catcher($self);
|
||||||
|
@ -788,6 +792,7 @@ sub make_model {
|
||||||
input_file => $plater_object->input_file,
|
input_file => $plater_object->input_file,
|
||||||
config => $plater_object->config,
|
config => $plater_object->config,
|
||||||
layer_height_ranges => $plater_object->layer_height_ranges,
|
layer_height_ranges => $plater_object->layer_height_ranges,
|
||||||
|
material_mapping => $plater_object->material_mapping,
|
||||||
);
|
);
|
||||||
foreach my $volume (@{$model_object->volumes}) {
|
foreach my $volume (@{$model_object->volumes}) {
|
||||||
$new_model_object->add_volume(
|
$new_model_object->add_volume(
|
||||||
|
@ -834,7 +839,6 @@ sub on_thumbnail_made {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my ($obj_idx) = @_;
|
my ($obj_idx) = @_;
|
||||||
|
|
||||||
$self->{objects}[$obj_idx]->free_model_object;
|
|
||||||
$self->recenter;
|
$self->recenter;
|
||||||
$self->{canvas}->Refresh;
|
$self->{canvas}->Refresh;
|
||||||
}
|
}
|
||||||
|
@ -1221,7 +1225,8 @@ use Slic3r::Geometry qw(X Y Z MIN MAX deg2rad);
|
||||||
has 'name' => (is => 'rw', required => 1);
|
has 'name' => (is => 'rw', required => 1);
|
||||||
has 'input_file' => (is => 'rw', required => 1);
|
has 'input_file' => (is => 'rw', required => 1);
|
||||||
has 'input_file_object_id' => (is => 'rw'); # undef means keep model object
|
has 'input_file_object_id' => (is => 'rw'); # undef means keep model object
|
||||||
has 'model_object' => (is => 'rw', required => 1, trigger => 1);
|
has 'model' => (is => 'rw', required => 1, trigger => \&_trigger_model_object);
|
||||||
|
has 'model_object_idx' => (is => 'rw', required => 1, trigger => \&_trigger_model_object);
|
||||||
has 'bounding_box' => (is => 'rw'); # 3D bb of original object (aligned to origin) with no rotation or scaling
|
has 'bounding_box' => (is => 'rw'); # 3D bb of original object (aligned to origin) with no rotation or scaling
|
||||||
has 'convex_hull' => (is => 'rw'); # 2D convex hull of original object (aligned to origin) with no rotation or scaling
|
has 'convex_hull' => (is => 'rw'); # 2D convex hull of original object (aligned to origin) with no rotation or scaling
|
||||||
has 'scale' => (is => 'rw', default => sub { 1 }, trigger => \&_transform_thumbnail);
|
has 'scale' => (is => 'rw', default => sub { 1 }, trigger => \&_transform_thumbnail);
|
||||||
|
@ -1232,6 +1237,7 @@ has 'transformed_thumbnail' => (is => 'rw');
|
||||||
has 'thumbnail_scaling_factor' => (is => 'rw', trigger => \&_transform_thumbnail);
|
has 'thumbnail_scaling_factor' => (is => 'rw', trigger => \&_transform_thumbnail);
|
||||||
has 'config' => (is => 'rw', default => sub { Slic3r::Config->new });
|
has 'config' => (is => 'rw', default => sub { Slic3r::Config->new });
|
||||||
has 'layer_height_ranges' => (is => 'rw', default => sub { [] }); # [ z_min, z_max, layer_height ]
|
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 'mesh_stats' => (is => 'rw');
|
||||||
|
|
||||||
# statistics
|
# statistics
|
||||||
|
@ -1242,16 +1248,17 @@ has 'is_manifold' => (is => 'rw');
|
||||||
|
|
||||||
sub _trigger_model_object {
|
sub _trigger_model_object {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
if ($self->model_object) {
|
if ($self->model && defined $self->model_object_idx) {
|
||||||
$self->model_object->align_to_origin;
|
my $model_object = $self->model->objects->[$self->model_object_idx];
|
||||||
$self->bounding_box($self->model_object->bounding_box);
|
$model_object->align_to_origin;
|
||||||
|
$self->bounding_box($model_object->bounding_box);
|
||||||
|
|
||||||
my $mesh = $self->model_object->mesh;
|
my $mesh = $model_object->mesh;
|
||||||
$self->convex_hull(Slic3r::Polygon->new(@{Math::ConvexHull::MonotoneChain::convex_hull($mesh->used_vertices)}));
|
$self->convex_hull(Slic3r::Polygon->new(@{Math::ConvexHull::MonotoneChain::convex_hull($mesh->used_vertices)}));
|
||||||
$self->facets(scalar @{$mesh->facets});
|
$self->facets(scalar @{$mesh->facets});
|
||||||
$self->vertices(scalar @{$mesh->vertices});
|
$self->vertices(scalar @{$mesh->vertices});
|
||||||
|
|
||||||
$self->materials($self->model_object->materials_count);
|
$self->materials($model_object->materials_count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1290,18 +1297,21 @@ sub free_model_object {
|
||||||
|
|
||||||
# only delete mesh from memory if we can retrieve it from the original file
|
# only delete mesh from memory if we can retrieve it from the original file
|
||||||
return unless $self->input_file && defined $self->input_file_object_id;
|
return unless $self->input_file && defined $self->input_file_object_id;
|
||||||
$self->model_object(undef);
|
$self->model(undef);
|
||||||
|
$self->model_object_idx(undef);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub get_model_object {
|
sub get_model_object {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
|
||||||
my $object = $self->model_object;
|
if ($self->model) {
|
||||||
if (!$object) {
|
return $self->model->objects->[$self->model_object_idx];
|
||||||
my $model = Slic3r::Model->read_from_file($self->input_file);
|
|
||||||
$object = $model->objects->[$self->input_file_object_id];
|
|
||||||
}
|
}
|
||||||
return $object;
|
|
||||||
|
return Slic3r::Model
|
||||||
|
->read_from_file($self->input_file)
|
||||||
|
->objects
|
||||||
|
->[$self->input_file_object_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
sub instances_count {
|
sub instances_count {
|
||||||
|
@ -1312,7 +1322,7 @@ sub instances_count {
|
||||||
sub make_thumbnail {
|
sub make_thumbnail {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
|
||||||
my $mesh = $self->model_object->mesh; # $self->model_object is already aligned to origin
|
my $mesh = $self->get_model_object->mesh; # $self->model_object is already aligned to origin
|
||||||
my $thumbnail = Slic3r::ExPolygon::Collection->new;
|
my $thumbnail = Slic3r::ExPolygon::Collection->new;
|
||||||
if (@{$mesh->facets} <= 5000) {
|
if (@{$mesh->facets} <= 5000) {
|
||||||
$thumbnail->append(@{ $mesh->horizontal_projection });
|
$thumbnail->append(@{ $mesh->horizontal_projection });
|
||||||
|
@ -1331,7 +1341,6 @@ sub make_thumbnail {
|
||||||
|
|
||||||
$thumbnail->scale(&Slic3r::SCALING_FACTOR);
|
$thumbnail->scale(&Slic3r::SCALING_FACTOR);
|
||||||
$self->thumbnail($thumbnail); # ignored in multi-threaded environments
|
$self->thumbnail($thumbnail); # ignored in multi-threaded environments
|
||||||
$self->free_model_object;
|
|
||||||
|
|
||||||
return $thumbnail;
|
return $thumbnail;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ sub new {
|
||||||
$self->{tabpanel} = Wx::Notebook->new($self, -1, wxDefaultPosition, wxDefaultSize, wxNB_TOP | wxTAB_TRAVERSAL);
|
$self->{tabpanel} = Wx::Notebook->new($self, -1, wxDefaultPosition, wxDefaultSize, wxNB_TOP | wxTAB_TRAVERSAL);
|
||||||
$self->{tabpanel}->AddPage($self->{settings} = Slic3r::GUI::Plater::ObjectDialog::SettingsTab->new($self->{tabpanel}, object => $self->{object}), "Settings");
|
$self->{tabpanel}->AddPage($self->{settings} = Slic3r::GUI::Plater::ObjectDialog::SettingsTab->new($self->{tabpanel}, object => $self->{object}), "Settings");
|
||||||
$self->{tabpanel}->AddPage($self->{layers} = Slic3r::GUI::Plater::ObjectDialog::LayersTab->new($self->{tabpanel}, object => $self->{object}), "Layers");
|
$self->{tabpanel}->AddPage($self->{layers} = Slic3r::GUI::Plater::ObjectDialog::LayersTab->new($self->{tabpanel}, object => $self->{object}), "Layers");
|
||||||
|
$self->{tabpanel}->AddPage($self->{materials} = Slic3r::GUI::Plater::ObjectDialog::MaterialsTab->new($self->{tabpanel}, object => $self->{object}), "Materials");
|
||||||
|
|
||||||
my $buttons = $self->CreateStdDialogButtonSizer(wxOK);
|
my $buttons = $self->CreateStdDialogButtonSizer(wxOK);
|
||||||
EVT_BUTTON($self, wxID_OK, sub {
|
EVT_BUTTON($self, wxID_OK, sub {
|
||||||
|
@ -25,6 +26,7 @@ sub new {
|
||||||
|
|
||||||
# notify tabs
|
# notify tabs
|
||||||
$self->{layers}->Closing;
|
$self->{layers}->Closing;
|
||||||
|
$self->{materials}->Closing;
|
||||||
|
|
||||||
$self->EndModal(wxID_OK);
|
$self->EndModal(wxID_OK);
|
||||||
});
|
});
|
||||||
|
@ -254,4 +256,68 @@ sub _get_ranges {
|
||||||
return sort { $a->[0] <=> $b->[0] } @ranges;
|
return sort { $a->[0] <=> $b->[0] } @ranges;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
package Slic3r::GUI::Plater::ObjectDialog::MaterialsTab;
|
||||||
|
use Wx qw(:dialog :id :misc :sizer :systemsettings :button :icon);
|
||||||
|
use Wx::Grid;
|
||||||
|
use Wx::Event qw(EVT_BUTTON);
|
||||||
|
use base 'Wx::Panel';
|
||||||
|
|
||||||
|
sub new {
|
||||||
|
my $class = shift;
|
||||||
|
my ($parent, %params) = @_;
|
||||||
|
my $self = $class->SUPER::new($parent, -1, wxDefaultPosition, wxDefaultSize);
|
||||||
|
$self->{object} = $params{object};
|
||||||
|
|
||||||
|
$self->{sizer} = Wx::BoxSizer->new(wxVERTICAL);
|
||||||
|
|
||||||
|
# descriptive text
|
||||||
|
{
|
||||||
|
my $label = Wx::StaticText->new($self, -1, "In this section you can assign object materials to your extruders.",
|
||||||
|
wxDefaultPosition, [-1, 25]);
|
||||||
|
$label->SetFont(Wx::SystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
|
||||||
|
$self->{sizer}->Add($label, 0, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
# get unique materials used in this object
|
||||||
|
$self->{materials} = [ $self->{object}->get_model_object->unique_materials ];
|
||||||
|
|
||||||
|
# build an OptionsGroup
|
||||||
|
$self->{mapping} = {
|
||||||
|
(map { $self->{materials}[$_] => $_+1 } 0..$#{ $self->{materials} }), # defaults
|
||||||
|
%{$self->{object}->material_mapping},
|
||||||
|
};
|
||||||
|
my $optgroup = Slic3r::GUI::OptionsGroup->new(
|
||||||
|
parent => $self,
|
||||||
|
title => 'Extruders',
|
||||||
|
label_width => 300,
|
||||||
|
options => [
|
||||||
|
map {
|
||||||
|
my $i = $_;
|
||||||
|
my $material_id = $self->{materials}[$i];
|
||||||
|
{
|
||||||
|
opt_key => "material_extruder_$_",
|
||||||
|
type => 'i',
|
||||||
|
label => $self->{object}->get_model_object->model->get_material_name($material_id),
|
||||||
|
min => 1,
|
||||||
|
default => $self->{mapping}{$material_id},
|
||||||
|
on_change => sub { $self->{mapping}{$material_id} = $_[0] },
|
||||||
|
}
|
||||||
|
} 0..$#{ $self->{materials} }
|
||||||
|
],
|
||||||
|
);
|
||||||
|
$self->{sizer}->Add($optgroup->sizer, 0, wxEXPAND | wxALL, 10);
|
||||||
|
|
||||||
|
$self->SetSizer($self->{sizer});
|
||||||
|
$self->{sizer}->SetSizeHints($self);
|
||||||
|
|
||||||
|
return $self;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub Closing {
|
||||||
|
my $self = shift;
|
||||||
|
|
||||||
|
# save mappings into the plater object
|
||||||
|
$self->{object}->material_mapping($self->{mapping});
|
||||||
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
|
@ -285,6 +285,20 @@ sub print_info {
|
||||||
$_->print_info for @{$self->objects};
|
$_->print_info for @{$self->objects};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub get_material_name {
|
||||||
|
my $self = shift;
|
||||||
|
my ($material_id) = @_;
|
||||||
|
|
||||||
|
my $name;
|
||||||
|
if (exists $self->materials->{$material_id}) {
|
||||||
|
$name //= $self->materials->{$material_id}->attributes->{$_} for qw(Name name);
|
||||||
|
} elsif ($material_id eq '_') {
|
||||||
|
$name = 'Default material';
|
||||||
|
}
|
||||||
|
$name //= $material_id;
|
||||||
|
return $name;
|
||||||
|
}
|
||||||
|
|
||||||
package Slic3r::Model::Region;
|
package Slic3r::Model::Region;
|
||||||
use Moo;
|
use Moo;
|
||||||
|
|
||||||
|
@ -306,6 +320,7 @@ has 'volumes' => (is => 'ro', default => sub { [] });
|
||||||
has 'instances' => (is => 'rw');
|
has 'instances' => (is => 'rw');
|
||||||
has 'config' => (is => 'rw', default => sub { Slic3r::Config->new });
|
has 'config' => (is => 'rw', default => sub { Slic3r::Config->new });
|
||||||
has 'layer_height_ranges' => (is => 'rw', default => sub { [] }); # [ z_min, z_max, layer_height ]
|
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 'mesh_stats' => (is => 'rw');
|
||||||
has '_bounding_box' => (is => 'rw');
|
has '_bounding_box' => (is => 'rw');
|
||||||
|
|
||||||
|
@ -430,6 +445,14 @@ sub materials_count {
|
||||||
return scalar keys %materials;
|
return scalar keys %materials;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub unique_materials {
|
||||||
|
my $self = shift;
|
||||||
|
|
||||||
|
my %materials = ();
|
||||||
|
$materials{ $_->material_id // '_' } = 1 for @{$self->volumes};
|
||||||
|
return sort keys %materials;
|
||||||
|
}
|
||||||
|
|
||||||
sub facets_count {
|
sub facets_count {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
return sum(map $_->facets_count, @{$self->volumes});
|
return sum(map $_->facets_count, @{$self->volumes});
|
||||||
|
|
|
@ -91,18 +91,6 @@ sub add_model {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my ($model) = @_;
|
my ($model) = @_;
|
||||||
|
|
||||||
# append/merge materials and preserve a mapping between the original material ID
|
|
||||||
# and our numeric material index
|
|
||||||
my %materials = ();
|
|
||||||
{
|
|
||||||
my @material_ids = sort keys %{$model->materials};
|
|
||||||
@material_ids = (0) if !@material_ids;
|
|
||||||
for (my $i = $self->regions_count; $i < @material_ids; $i++) {
|
|
||||||
push @{$self->regions}, Slic3r::Print::Region->new;
|
|
||||||
$materials{$material_ids[$i]} = $#{$self->regions};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# optimization: if avoid_crossing_perimeters is enabled, split
|
# optimization: if avoid_crossing_perimeters is enabled, split
|
||||||
# this mesh into distinct objects so that we reduce the complexity
|
# this mesh into distinct objects so that we reduce the complexity
|
||||||
# of the graphs
|
# of the graphs
|
||||||
|
@ -112,6 +100,7 @@ sub add_model {
|
||||||
# -- thing before the split.
|
# -- thing before the split.
|
||||||
###$model->split_meshes if $Slic3r::Config->avoid_crossing_perimeters && !$Slic3r::Config->complete_objects;
|
###$model->split_meshes if $Slic3r::Config->avoid_crossing_perimeters && !$Slic3r::Config->complete_objects;
|
||||||
|
|
||||||
|
my %unmapped_materials = ();
|
||||||
foreach my $object (@{ $model->objects }) {
|
foreach my $object (@{ $model->objects }) {
|
||||||
# we align object to origin before applying transformations
|
# we align object to origin before applying transformations
|
||||||
my @align = $object->align_to_origin;
|
my @align = $object->align_to_origin;
|
||||||
|
@ -119,13 +108,26 @@ sub add_model {
|
||||||
# extract meshes by material
|
# extract meshes by material
|
||||||
my @meshes = (); # by region_id
|
my @meshes = (); # by region_id
|
||||||
foreach my $volume (@{$object->volumes}) {
|
foreach my $volume (@{$object->volumes}) {
|
||||||
my $region_id = defined $volume->material_id ? $materials{$volume->material_id} : 0;
|
my $region_id;
|
||||||
|
if (defined $volume->material_id) {
|
||||||
|
if ($object->material_mapping) {
|
||||||
|
$region_id = $object->material_mapping->{$volume->material_id} - 1
|
||||||
|
if defined $object->material_mapping->{$volume->material_id};
|
||||||
|
}
|
||||||
|
$region_id //= $unmapped_materials{$volume->material_id};
|
||||||
|
if (!defined $region_id) {
|
||||||
|
$region_id = $unmapped_materials{$volume->material_id} = scalar(keys %unmapped_materials);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$region_id //= 0;
|
||||||
|
|
||||||
my $mesh = $volume->mesh->clone;
|
my $mesh = $volume->mesh->clone;
|
||||||
# should the object contain multiple volumes of the same material, merge them
|
# should the object contain multiple volumes of the same material, merge them
|
||||||
$meshes[$region_id] = $meshes[$region_id]
|
$meshes[$region_id] = $meshes[$region_id]
|
||||||
? Slic3r::TriangleMesh->merge($meshes[$region_id], $mesh)
|
? Slic3r::TriangleMesh->merge($meshes[$region_id], $mesh)
|
||||||
: $mesh;
|
: $mesh;
|
||||||
}
|
}
|
||||||
|
$self->regions->[$_] //= Slic3r::Print::Region->new for 0..$#meshes;
|
||||||
|
|
||||||
foreach my $mesh (grep $_, @meshes) {
|
foreach my $mesh (grep $_, @meshes) {
|
||||||
$mesh->check_manifoldness;
|
$mesh->check_manifoldness;
|
||||||
|
|
|
@ -143,7 +143,7 @@ sub slice {
|
||||||
|
|
||||||
# process facets
|
# process facets
|
||||||
for my $region_id (0 .. $#{$self->meshes}) {
|
for my $region_id (0 .. $#{$self->meshes}) {
|
||||||
my $mesh = $self->meshes->[$region_id]; # ignore undef meshes
|
my $mesh = $self->meshes->[$region_id] // next; # ignore undef meshes
|
||||||
|
|
||||||
my %lines = (); # layer_id => [ lines ]
|
my %lines = (); # layer_id => [ lines ]
|
||||||
my $apply_lines = sub {
|
my $apply_lines = sub {
|
||||||
|
|
Loading…
Reference in a new issue