Incomplete work for refactoring regions and flows

xs-bb
Alessandro Ranellucci 2013-12-30 18:28:41 +01:00
parent 231bffa99b
commit beb1baa096
13 changed files with 297 additions and 148 deletions

View File

@ -175,6 +175,22 @@ sub setenv {
}
}
sub equals {
my ($self, $other) = @_;
return @{ $self->diff($other) } == 0;
}
sub diff {
my ($self, $other) = @_;
my @diff = ();
foreach my $opt_key (sort @{$self->get_keys}) {
push @diff, $opt_key
if !$other->has($opt_key) || $other->serialize($opt_key) ne $self->serialize($opt_key);
}
return [@diff];
}
# this method is idempotent by design
sub validate {
my $self = shift;

View File

@ -1,6 +1,12 @@
package Slic3r::Extruder;
use Moo;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(EXTRUDER_ROLE_PERIMETER EXTRUDER_ROLE_INFILL EXTRUDER_ROLE_SUPPORT_MATERIAL
EXTRUDER_ROLE_SUPPORT_MATERIAL_INTERFACE);
our %EXPORT_TAGS = (roles => \@EXPORT_OK);
use Slic3r::Geometry qw(PI scale);
use constant OPTIONS => [qw(
@ -14,7 +20,6 @@ has 'id' => (is => 'rw', required => 1);
has $_ => (is => 'ro', required => 1) for @{&OPTIONS};
has 'config'=> (is => 'ro', required => 1);
has 'bridge_flow' => (is => 'lazy');
has 'E' => (is => 'rw', default => sub {0} );
has 'absolute_E' => (is => 'rw', default => sub {0} );
has 'retracted' => (is => 'rw', default => sub {0} );
@ -23,14 +28,10 @@ has 'e_per_mm3' => (is => 'lazy');
has 'retract_speed_mm_min' => (is => 'lazy');
has '_mm3_per_mm_cache' => (is => 'ro', default => sub {{}});
sub _build_bridge_flow {
my $self = shift;
return Slic3r::Flow::Bridge->new(
nozzle_diameter => $self->nozzle_diameter,
bridge_flow_ratio => $self->config->bridge_flow_ratio,
);
}
use constant EXTRUDER_ROLE_PERIMETER => 1;
use constant EXTRUDER_ROLE_INFILL => 2;
use constant EXTRUDER_ROLE_SUPPORT_MATERIAL => 3;
use constant EXTRUDER_ROLE_SUPPORT_MATERIAL_INTERFACE => 4;
sub _build_e_per_mm3 {
my $self = shift;

View File

@ -1,48 +1,73 @@
package Slic3r::Flow;
use Moo;
use Slic3r::Geometry qw(PI scale);
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(FLOW_ROLE_PERIMETER FLOW_ROLE_INFILL FLOW_ROLE_SOLID_INFILL FLOW_ROLE_TOP_SOLID_INFILL
FLOW_ROLE_SUPPORT_MATERIAL FLOW_ROLE_SUPPORT_MATERIAL_INTERFACE);
our %EXPORT_TAGS = (roles => \@EXPORT_OK);
has 'nozzle_diameter' => (is => 'ro', required => 1);
has 'layer_height' => (is => 'ro', required => 1);
has 'role' => (is => 'ro', default => sub { '' });
use Slic3r::Geometry qw(PI);
has 'width' => (is => 'rwp', builder => 1);
has 'spacing' => (is => 'lazy');
has 'width' => (is => 'ro');
has 'spacing' => (is => 'ro');
has 'scaled_width' => (is => 'lazy');
has 'scaled_spacing' => (is => 'lazy');
sub BUILD {
my $self = shift;
use constant FLOW_ROLE_PERIMETER => 1;
use constant FLOW_ROLE_INFILL => 2;
use constant FLOW_ROLE_SOLID_INFILL => 3;
use constant FLOW_ROLE_TOP_SOLID_INFILL => 4;
use constant FLOW_ROLE_SUPPORT_MATERIAL => 5;
use constant FLOW_ROLE_SUPPORT_MATERIAL_INTERFACE => 6;
sub BUILDARGS {
my ($self, %args) = @_;
if ($self->width =~ /^(\d+(?:\.\d+)?)%$/) {
$self->_set_width($self->layer_height * $1 / 100);
# the constructor can take two sets of arguments:
# - width (only absolute value), spacing
# - width (abs/%/0), role, nozzle_diameter, layer_height, bridge_flow_ratio
# (if bridge_flow_ratio == 0, we return a non-bridge flow)
if (exists $args{role}) {
if ($args{width} eq '0') {
$args{width} = $self->_width(@args{qw(role nozzle_diameter layer_height bridge_flow_ratio)});
} elsif ($args{width} =~ /^(\d+(?:\.\d+)?)%$/) {
$args{width} = $args{layer_height} * $1 / 100;
}
$args{spacing} = $self->_spacing(@args{qw(width nozzle_diameter layer_height bridge_flow_ratio)});
%args = @args{qw(width spacing)};
}
$self->_set_width($self->_build_width) if $self->width == 0; # auto
return {%args};
}
sub _build_width {
my $self = shift;
sub _width {
my ($self, $role, $nozzle_diameter, $layer_height, $bridge_flow_ratio) = @_;
if ($bridge_flow_ratio > 0) {
return sqrt($bridge_flow_ratio * ($nozzle_diameter**2));
}
# here we calculate a sane default by matching the flow speed (at the nozzle) and the feed rate
my $volume = ($self->nozzle_diameter**2) * PI/4;
my $shape_threshold = $self->nozzle_diameter * $self->layer_height + ($self->layer_height**2) * PI/4;
my $volume = ($nozzle_diameter**2) * PI/4;
my $shape_threshold = $nozzle_diameter * $layer_height + ($layer_height**2) * PI/4;
my $width;
if ($volume >= $shape_threshold) {
# rectangle with semicircles at the ends
$width = (($self->nozzle_diameter**2) * PI + ($self->layer_height**2) * (4 - PI)) / (4 * $self->layer_height);
$width = (($nozzle_diameter**2) * PI + ($layer_height**2) * (4 - PI)) / (4 * $layer_height);
} else {
# rectangle with squished semicircles at the ends
$width = $self->nozzle_diameter * ($self->nozzle_diameter/$self->layer_height - 4/PI + 1);
$width = $nozzle_diameter * ($nozzle_diameter/$layer_height - 4/PI + 1);
}
my $min = $self->nozzle_diameter * 1.05;
my $min = $nozzle_diameter * 1.05;
my $max;
if ($self->role eq 'perimeter' || $self->role eq 'support_material') {
$min = $max = $self->nozzle_diameter;
} elsif ($self->role ne 'infill') {
if ($role == FLOW_ROLE_PERIMETER || $role == FLOW_ROLE_SUPPORT_MATERIAL) {
$min = $max = $nozzle_diameter;
} elsif ($role != FLOW_ROLE_INFILL) {
# do not limit width for sparse infill so that we use full native flow for it
$max = $self->nozzle_diameter * 1.7;
$max = $nozzle_diameter * 1.7;
}
$width = $max if defined($max) && $width > $max;
$width = $min if $width < $min;
@ -50,59 +75,41 @@ sub _build_width {
return $width;
}
sub _build_spacing {
my $self = shift;
sub _spacing {
my ($self, $width, $nozzle_diameter, $layer_height, $bridge_flow_ratio) = @_;
if ($bridge_flow_ratio > 0) {
return $width + 0.05;
}
my $min_flow_spacing;
if ($self->width >= ($self->nozzle_diameter + $self->layer_height)) {
if ($width >= ($nozzle_diameter + $layer_height)) {
# rectangle with semicircles at the ends
$min_flow_spacing = $self->width - $self->layer_height * (1 - PI/4);
$min_flow_spacing = $width - $layer_height * (1 - PI/4);
} else {
# rectangle with shrunk semicircles at the ends
$min_flow_spacing = $self->nozzle_diameter * (1 - PI/4) + $self->width * PI/4;
$min_flow_spacing = $nozzle_diameter * (1 - PI/4) + $width * PI/4;
}
return $self->width - &Slic3r::OVERLAP_FACTOR * ($self->width - $min_flow_spacing);
return $width - &Slic3r::OVERLAP_FACTOR * ($width - $min_flow_spacing);
}
sub clone {
my $self = shift;
return (ref $self)->new(
nozzle_diameter => $self->nozzle_diameter,
layer_height => $self->layer_height,
@_,
width => $self->width,
spacing => $self->spacing,
);
}
sub _build_scaled_width {
my $self = shift;
return scale $self->width;
return Slic3r::Geometry::scale($self->width);
}
sub _build_scaled_spacing {
my $self = shift;
return scale $self->spacing;
}
package Slic3r::Flow::Bridge;
use Moo;
extends 'Slic3r::Flow';
# layer_height is not required in this case
has '+layer_height' => (is => 'ro', required => 0);
has 'bridge_flow_ratio' => (is => 'ro', required => 1);
use Slic3r::Geometry qw(PI);
sub _build_width {
my $self = shift;
return sqrt($self->bridge_flow_ratio * ($self->nozzle_diameter**2));
}
sub _build_spacing {
my $self = shift;
return $self->width + 0.05;
return Slic3r::Geometry::scale($self->spacing);
}
1;

View File

@ -638,7 +638,6 @@ sub split_object {
input_file => $current_model_object->input_file,
config => $current_model_object->config->clone,
layer_height_ranges => $current_model_object->layer_height_ranges, # TODO: clone this
material_mapping => $current_model_object->material_mapping, # TODO: clone this
);
$model_object->add_volume(
mesh => $mesh,

View File

@ -324,7 +324,12 @@ sub Closing {
my $self = shift;
# save mappings into the plater object
$self->model_object->material_mapping($self->{mapping});
foreach my $volume (@{$self->model_object}) {
if (defined $volume->material_id) {
my $config = $self->model_object->model->materials->{ $volume->material_id }->config;
$config->set('extruder', $self->{mapping}{ $volume->material_id });
}
}
}
1;

View File

@ -146,7 +146,10 @@ sub quick_slice {
}
$model->center_instances_around_point($config->print_center);
$print->add_model_object($_) for @{ $model->objects };
foreach my $model_object (@{$model->objects}) {
$print->auto_assign_extruders($model_object);
$print->add_model_object($model_object);
}
$print->validate;
# select output file

View File

@ -3,6 +3,7 @@ use Moo;
use List::Util qw(sum first);
use Slic3r::ExtrusionPath ':roles';
use Slic3r::Flow ':roles';
use Slic3r::Geometry qw(PI A B scale unscale chained_path points_coincide);
use Slic3r::Geometry::Clipper qw(union_ex diff_ex intersection_ex
offset offset2 offset2_ex union_pt diff intersection
@ -17,10 +18,6 @@ has 'layer' => (
handles => [qw(id slice_z print_z height flow config)],
);
has 'region' => (is => 'ro', required => 1, handles => [qw(extruders)]);
has 'perimeter_flow' => (is => 'rw');
has 'infill_flow' => (is => 'rw');
has 'solid_infill_flow' => (is => 'rw');
has 'top_infill_flow' => (is => 'rw');
has 'infill_area_threshold' => (is => 'lazy');
has 'overhang_width' => (is => 'lazy');
@ -40,43 +37,26 @@ has 'perimeters' => (is => 'rw', default => sub { Slic3r::ExtrusionPath::Collect
# ordered collection of extrusion paths to fill surfaces
has 'fills' => (is => 'rw', default => sub { Slic3r::ExtrusionPath::Collection->new });
sub BUILD {
my $self = shift;
$self->_update_flows;
}
sub _trigger_layer {
my $self = shift;
$self->_update_flows;
}
sub _update_flows {
my $self = shift;
return if !$self->region;
if ($self->id == 0) {
for (qw(perimeter infill solid_infill top_infill)) {
my $method = "${_}_flow";
$self->$method
($self->region->first_layer_flows->{$_} || $self->region->flows->{$_});
}
} else {
$self->perimeter_flow($self->region->flows->{perimeter});
$self->infill_flow($self->region->flows->{infill});
$self->solid_infill_flow($self->region->flows->{solid_infill});
$self->top_infill_flow($self->region->flows->{top_infill});
}
}
sub _build_overhang_width {
my $self = shift;
my $threshold_rad = PI/2 - atan2($self->perimeter_flow->width / $self->height / 2, 1);
my $threshold_rad = PI/2 - atan2($self->flow(FLOW_ROLE_PERIMETER)->width / $self->height / 2, 1);
return scale($self->height * ((cos $threshold_rad) / (sin $threshold_rad)));
}
sub _build_infill_area_threshold {
my $self = shift;
return $self->solid_infill_flow->scaled_spacing ** 2;
return $self->flow(FLOW_ROLE_SOLID_INFILL)->scaled_spacing ** 2;
}
sub flow {
my ($self, $role, $bridge, $width) = @_;
return $self->region->flow(
$role,
$self->layer->height,
$bridge // 0,
$self->layer->id == 0,
$width,
);
}
# build polylines from lines
@ -145,10 +125,11 @@ sub _merge_loops {
sub make_perimeters {
my $self = shift;
my $pwidth = $self->perimeter_flow->scaled_width;
my $pspacing = $self->perimeter_flow->scaled_spacing;
my $ispacing = $self->solid_infill_flow->scaled_spacing;
my $gap_area_threshold = $self->perimeter_flow->scaled_width ** 2;
my $perimeter_flow = $self->flow(FLOW_ROLE_PERIMETER);
my $pwidth = $perimeter_flow->scaled_width;
my $pspacing = $perimeter_flow->scaled_spacing;
my $ispacing = $self->flow(FLOW_ROLE_SOLID_INFILL)->scaled_spacing;
my $gap_area_threshold = $pwidth ** 2;
$self->perimeters->clear;
$self->fill_surfaces->clear;
@ -284,7 +265,7 @@ sub make_perimeters {
push @loops, Slic3r::ExtrusionLoop->new(
polygon => $polygon,
role => $role,
flow_spacing => $self->perimeter_flow->spacing,
flow_spacing => $perimeter_flow->spacing,
);
}
return @loops;
@ -311,7 +292,7 @@ sub make_perimeters {
next if $p->length <= $pspacing * 2;
my %params = (
role => EXTR_ROLE_EXTERNAL_PERIMETER,
flow_spacing => $self->perimeter_flow->spacing,
flow_spacing => $perimeter_flow->spacing,
);
push @paths, $p->isa('Slic3r::Polygon')
? Slic3r::ExtrusionLoop->new(polygon => $p, %params)
@ -345,10 +326,10 @@ sub _fill_gaps {
# we could try with 1.5*$w for example, but that doesn't work well for zigzag fill
# because it tends to create very sparse points along the gap when the infill direction
# is not parallel to the gap (1.5*$w thus may only work well with a straight line)
my $w = $self->perimeter_flow->width;
my $w = $self->flow(FLOW_ROLE_PERIMETER)->width;
my @widths = ($w, 0.4 * $w); # worth trying 0.2 too?
foreach my $width (@widths) {
my $flow = $self->perimeter_flow->clone(width => $width);
my $flow = $self->flow(FLOW_ROLE_PERIMETER, 0, $width);
# extract the gaps having this width
my @this_width = map @{$_->offset_ex(+0.5*$flow->scaled_width)},
@ -499,7 +480,10 @@ sub process_external_surfaces {
sub _detect_bridge_direction {
my ($self, $expolygon, $lower_layer) = @_;
my $grown = $expolygon->offset_ex(+$self->perimeter_flow->scaled_width);
my $perimeter_flow = $self->flow(FLOW_ROLE_PERIMETER);
my $infill_flow = $self->flow(FLOW_ROLE_INFILL);
my $grown = $expolygon->offset_ex(+$perimeter_flow->scaled_width);
my @lower = @{$lower_layer->slices}; # expolygons
# detect what edges lie on lower slices
@ -554,7 +538,7 @@ sub _detect_bridge_direction {
}
} elsif (@edges) {
# inset the bridge expolygon; we'll use this one to clip our test lines
my $inset = $expolygon->offset_ex($self->infill_flow->scaled_width);
my $inset = $expolygon->offset_ex($infill_flow->scaled_width);
# detect anchors as intersection between our bridge expolygon and the lower slices
my $anchors = intersection_ex(
@ -568,7 +552,7 @@ sub _detect_bridge_direction {
# endpoints within anchors
my %directions = (); # angle => score
my $angle_increment = PI/36; # 5°
my $line_increment = $self->infill_flow->scaled_width;
my $line_increment = $infill_flow->scaled_width;
for (my $angle = 0; $angle <= PI; $angle += $angle_increment) {
# rotate everything - the center point doesn't matter
$_->rotate($angle, [0,0]) for @$inset, @$anchors;

View File

@ -44,7 +44,6 @@ sub add_object {
input_file => $object->input_file,
config => $object->config,
layer_height_ranges => $object->layer_height_ranges, # TODO: clone!
material_mapping => $object->material_mapping, # TODO: clone!
);
foreach my $volume (@{$object->volumes}) {
@ -324,6 +323,7 @@ use Moo;
has 'model' => (is => 'ro', weak_ref => 1, required => 1);
has 'attributes' => (is => 'rw', default => sub { {} });
has 'config' => (is => 'rw', default => sub { Slic3r::Config->new });
package Slic3r::Model::Object;
use Moo;
@ -338,7 +338,6 @@ 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 => region_idx }
has '_bounding_box' => (is => 'rw');
sub add_volume {

View File

@ -17,8 +17,6 @@ has 'objects' => (is => 'rw', default => sub {[]});
has 'status_cb' => (is => 'rw');
has 'extruders' => (is => 'rw', default => sub {[]});
has 'regions' => (is => 'rw', default => sub {[]});
has 'support_material_flow' => (is => 'rw');
has 'first_layer_support_material_flow' => (is => 'rw');
has 'has_support_material' => (is => 'lazy');
has '_state' => (is => 'ro', default => sub { Slic3r::Print::State->new });
@ -88,30 +86,37 @@ sub add_model_object {
my $self = shift;
my ($object, $obj_idx) = @_;
# read the material mapping provided by the model object, if any
my %matmap = %{ $object->material_mapping || {} };
$_-- for values %matmap; # extruders in the mapping are 1-indexed but we want 0-indexed
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;
# get the config applied to this volume
my $config;
if (defined $volume->material_id) {
if (!exists $matmap{ $volume->material_id }) {
# there's no mapping between this material and a region
$matmap{ $volume->material_id } = scalar(@{ $self->regions });
}
$region_id = $matmap{ $volume->material_id };
my $config = $object->model->materials->{ $volume->material_id }->config;
} else {
$region_id = 0;
$config = Slic3r::Config->new;
}
# find an existing print region with the same config
my $region_id;
foreach my $i (0..$#{$self->regions}) {
my $region = $self->regions->[$i];
if ($config->equals($region->config)) {
$region_id = $i;
last;
}
}
# if no region exists with the same config, create a new one
if (!defined $region_id) {
push @{$self->regions}, Slic3r::Print::Region->new(config => $config->clone);
$region_id = $#{$self->regions};
}
# assign volume to region
$volumes{$region_id} //= [];
push @{ $volumes{$region_id} }, $volume_id;
# instantiate region if it does not exist
$self->regions->[$region_id] //= Slic3r::Print::Region->new;
}
# initialize print object
@ -632,7 +637,7 @@ sub make_skirt {
my @extruded_length = (); # for each extruder
# TODO: use each extruder's own flow
my $spacing = $self->objects->[0]->layers->[0]->regions->[0]->perimeter_flow->spacing;
my $spacing = $self->flow(FLOW_ROLE_SUPPORT_MATERIAL)->spacing;
my $first_layer_height = $self->config->get_value('first_layer_height');
my @extruders_e_per_mm = ();
@ -673,7 +678,7 @@ sub make_brim {
$self->brim->clear; # method must be idempotent
my $flow = $self->objects->[0]->layers->[0]->regions->[0]->perimeter_flow;
my $flow = $self->flow(FLOW_ROLE_SUPPORT_MATERIAL);
my $grow_distance = $flow->scaled_width / 2;
my @islands = (); # array of polygons
@ -747,15 +752,24 @@ sub write_gcode {
for (qw(nozzle_diameter filament_diameter extrusion_multiplier)) {
printf $fh "; %s = %s\n", $_, $self->config->$_->[0];
}
printf $fh "; perimeters extrusion width = %.2fmm\n", $self->regions->[0]->flows->{perimeter}->width;
printf $fh "; infill extrusion width = %.2fmm\n", $self->regions->[0]->flows->{infill}->width;
printf $fh "; solid infill extrusion width = %.2fmm\n", $self->regions->[0]->flows->{solid_infill}->width;
printf $fh "; top infill extrusion width = %.2fmm\n", $self->regions->[0]->flows->{top_infill}->width;
printf $fh "; support material extrusion width = %.2fmm\n", $self->support_material_flow->width
if $self->support_material_flow;
printf $fh "; first layer extrusion width = %.2fmm\n", $self->regions->[0]->first_layer_flows->{perimeter}->width
if $self->regions->[0]->first_layer_flows->{perimeter};
print $fh "\n";
for my $region_id (0..$#{$self->regions}) {
printf $fh "; perimeters extrusion width = %.2fmm\n",
$self->regions->[$region_id]->flow(FLOW_ROLE_PERIMETER)->width;
printf $fh "; infill extrusion width = %.2fmm\n",
$self->regions->[$region_id]->flow(FLOW_ROLE_INFILL)->width;
printf $fh "; solid infill extrusion width = %.2fmm\n",
$self->regions->[$region_id]->flow(FLOW_ROLE_SOLID_INFILL)->width;
printf $fh "; top infill extrusion width = %.2fmm\n",
$self->regions->[$region_id]->flow(FLOW_ROLE_TOP_SOLID_INFILL)->width;
printf $fh "; support material extrusion width = %.2fmm\n",
$self->flow(FLOW_ROLE_SUPPORT_MATERIAL)->width
if $self->support_material_flow;
printf $fh "; first layer extrusion width = %.2fmm\n",
$self->flow(FLOW_ROLE_SUPPORT_MATERIAL, 0, 1)->width
if $self->regions->[0]->first_layer_flows->{perimeter};
print $fh "\n";
}
# set up our extruder object
my $gcodegen = Slic3r::GCode->new(
@ -1012,4 +1026,64 @@ sub invalidate_step {
keys %Slic3r::Print::State::prereqs;
}
# This method assigns extruders to the volumes having a material
# but not having extruders set in the material config.
sub auto_assign_extruders {
my ($self, $model_object) = @_;
my $extruders = scalar @{ $self->config->nozzle_diameter };
foreach my $i (0..$#{$model_object->volumes}) {
my $volume = $model_object->volumes->[$i];
if (defined $volume->material_id) {
my $material = $model_object->model->materials->{ $volume->material_id };
my $config = $material->config;
$config->set_ifndef('perimeters_extruder', $i);
$config->set_ifndef('infill_extruder', $i);
$config->set_ifndef('support_material_extruder', $i);
$config->set_ifndef('support_material_interface_extruder', $i);
}
}
}
sub flow {
my ($self, $role, $layer_height, $bridge, $first_layer, $width) = @_;
$bridge //= 0;
$first_layer //= 0;
# use the supplied custom width, if any
my $config_width = $width;
if (!defined $config_width) {
# get extrusion width from configuration
# (might be an absolute value, or a percent value, or zero for auto)
if ($first_layer) {
$config_width = $self->config->first_layer_extrusion_width;
} elsif ($role == FLOW_ROLE_SUPPORT_MATERIAL || $role == FLOW_ROLE_SUPPORT_MATERIAL_INTERFACE) {
$config_width = $self->config->support_material_extrusion_width;
} else {
die "Unknown role $role";
}
}
# get the configured nozzle_diameter for the extruder associated
# to the flow role requested
my $extruder; # 1-based
if ($role == FLOW_ROLE_SUPPORT_MATERIAL) {
$config_width = $self->config->support_material_extruder;
} elsif ($role == FLOW_ROLE_SUPPORT_MATERIAL_INTERFACE) {
$config_width = $self->config->support_material_interface_extruder;
} else {
die "Unknown role $role";
}
my $nozzle_diameter = $self->config->nozzle_diameter->[$extruder-1];
return Slic3r::Flow->new(
width => $config_width,
role => $role,
nozzle_diameter => $nozzle_diameter,
layer_height => $layer_height,
bridge_flow_ratio => ($bridge ? $self->config->bridge_flow_ratio : 0),
);
}
1;

View File

@ -861,9 +861,11 @@ sub generate_support_material {
return unless ($self->config->support_material || $self->config->raft_layers > 0)
&& $self->layer_count >= 2;
Slic3r::Print::SupportMaterial
->new(config => $self->config, flow => $self->print->support_material_flow)
->generate($self);
my $s = Slic3r::Print::SupportMaterial->new(
config => $self->config,
flow => $self->print->support_material_flow,
);
$s->generate($self);
}
sub _simplify_slices {

View File

@ -1,8 +1,60 @@
package Slic3r::Print::Region;
use Moo;
has 'extruders' => (is => 'rw', default => sub { {} }); # by role
has 'flows' => (is => 'rw', default => sub { {} }); # by role
has 'first_layer_flows' => (is => 'rw', default => sub { {} }); # by role
use Slic3r::Extruder ':roles';
use Slic3r::Flow ':roles';
# A Print::Region object represents a group of volumes to print
# sharing the same config (including the same assigned extruder(s))
has 'print' => (is => 'ro', required => 1, weak_ref => 1);
has 'config' => (is => 'ro', required => 1);
sub flow {
my ($self, $role, $layer_height, $bridge, $first_layer, $width) = @_;
$bridge //= 0;
$first_layer //= 0;
# use the supplied custom width, if any
my $config_width = $width;
if (!defined $config_width) {
# get extrusion width from configuration
# (might be an absolute value, or a percent value, or zero for auto)
if ($first_layer) {
$config_width = $self->config->first_layer_extrusion_width;
} elsif ($role == FLOW_ROLE_PERIMETER) {
$config_width = $self->config->perimeter_extrusion_width;
} elsif ($role == FLOW_ROLE_INFILL) {
$config_width = $self->config->infill_extrusion_width;
} elsif ($role == FLOW_ROLE_SOLID_INFILL) {
$config_width = $self->config->solid_infill_extrusion_width;
} elsif ($role == FLOW_ROLE_TOP_SOLID_INFILL) {
$config_width = $self->config->top_infill_extrusion_width;
} else {
die "Unknown role $role";
}
}
# get the configured nozzle_diameter for the extruder associated
# to the flow role requested
my $extruder; # 1-based
if ($role == FLOW_ROLE_PERIMETER) {
$config_width = $self->config->perimeter_extruder;
} elsif ($role == FLOW_ROLE_INFILL || $role == FLOW_ROLE_SOLID_INFILL || $role == FLOW_ROLE_TOP_SOLID_INFILL) {
$config_width = $self->config->infill_extruder;
} else {
die "Unknown role $role";
}
my $nozzle_diameter = $self->print->config->nozzle_diameter->[$extruder-1];
return Slic3r::Flow->new(
width => $config_width,
role => $role,
nozzle_diameter => $nozzle_diameter,
layer_height => $layer_height,
bridge_flow_ratio => ($bridge ? $self->config->bridge_flow_ratio : 0),
);
}
1;

View File

@ -159,7 +159,10 @@ if (@ARGV) { # slicing from command line
printf "=> %s\n", $message;
},
);
$print->add_model_object($_) for @{$model->objects};
foreach my $model_object (@{$model->objects}) {
$print->auto_assign_extruders($model_object);
$print->add_model_object($model_object);
}
undef $model; # free memory
$print->validate;
if ($opt{export_svg}) {

View File

@ -761,6 +761,7 @@ class PrintConfig : public StaticConfig
Options["infill_extruder"].label = "Infill extruder";
Options["infill_extruder"].tooltip = "The extruder to use when printing infill.";
Options["infill_extruder"].cli = "infill-extruder=i";
Options["infill_extruder"].shortcut.push_back("extruder");
Options["infill_extrusion_width"].type = coFloatOrPercent;
Options["infill_extrusion_width"].label = "Infill";
@ -878,6 +879,7 @@ class PrintConfig : public StaticConfig
Options["perimeter_extruder"].tooltip = "The extruder to use when printing perimeters.";
Options["perimeter_extruder"].cli = "perimeter-extruder=i";
Options["perimeter_extruder"].aliases.push_back("perimeters_extruder");
Options["perimeter_extruder"].shortcut.push_back("extruder");
Options["perimeter_extrusion_width"].type = coFloatOrPercent;
Options["perimeter_extrusion_width"].label = "Perimeters";
@ -1139,6 +1141,7 @@ class PrintConfig : public StaticConfig
Options["support_material_extruder"].label = "Support material extruder";
Options["support_material_extruder"].tooltip = "The extruder to use when printing support material. This affects brim and raft too.";
Options["support_material_extruder"].cli = "support-material-extruder=i";
Options["support_material_extruder"].shortcut.push_back("extruder");
Options["support_material_extrusion_width"].type = coFloatOrPercent;
Options["support_material_extrusion_width"].label = "Support material";
@ -1150,6 +1153,7 @@ class PrintConfig : public StaticConfig
Options["support_material_interface_extruder"].label = "Support material interface extruder";
Options["support_material_interface_extruder"].tooltip = "The extruder to use when printing support material interface. This affects raft too.";
Options["support_material_interface_extruder"].cli = "support-material-interface-extruder=i";
Options["support_material_interface_extruder"].shortcut.push_back("extruder");
Options["support_material_interface_layers"].type = coInt;
Options["support_material_interface_layers"].label = "Interface layers";