New --solid-infill-extruder option. Includes a refactoring of the strategy used to order layer extrusions according to their extruder and island; toolchanges and travel moves should be more optimized now. #618
This commit is contained in:
parent
d9cffeca4a
commit
e79aa2e81c
@ -353,6 +353,7 @@ The author of the Silk icon set is Mark James.
|
|||||||
--perimeter-extruder
|
--perimeter-extruder
|
||||||
Extruder to use for perimeters (1+, default: 1)
|
Extruder to use for perimeters (1+, default: 1)
|
||||||
--infill-extruder Extruder to use for infill (1+, default: 1)
|
--infill-extruder Extruder to use for infill (1+, default: 1)
|
||||||
|
--solid-infill-extruder Extruder to use for solid infill (1+, default: 1)
|
||||||
--support-material-extruder
|
--support-material-extruder
|
||||||
Extruder to use for support material (1+, default: 1)
|
Extruder to use for support material (1+, default: 1)
|
||||||
--support-material-interface-extruder
|
--support-material-interface-extruder
|
||||||
|
@ -225,28 +225,32 @@ sub make_fill {
|
|||||||
my $mm3_per_mm = $flow->mm3_per_mm;
|
my $mm3_per_mm = $flow->mm3_per_mm;
|
||||||
|
|
||||||
# save into layer
|
# save into layer
|
||||||
push @fills, my $collection = Slic3r::ExtrusionPath::Collection->new;
|
{
|
||||||
$collection->no_sort($params->{no_sort});
|
my $role = $is_bridge ? EXTR_ROLE_BRIDGE
|
||||||
|
: $is_solid ? (($surface->surface_type == S_TYPE_TOP) ? EXTR_ROLE_TOPSOLIDFILL : EXTR_ROLE_SOLIDFILL)
|
||||||
|
: EXTR_ROLE_FILL;
|
||||||
|
|
||||||
|
my $extrusion_height = $is_bridge ? $flow->width : $h;
|
||||||
|
|
||||||
|
push @fills, my $collection = Slic3r::ExtrusionPath::Collection->new($role);
|
||||||
|
$collection->no_sort($params->{no_sort});
|
||||||
|
$collection->append(
|
||||||
|
map Slic3r::ExtrusionPath->new(
|
||||||
|
polyline => $_,
|
||||||
|
role => $role,
|
||||||
|
mm3_per_mm => $mm3_per_mm,
|
||||||
|
width => $flow->width,
|
||||||
|
height => $extrusion_height,
|
||||||
|
), @polylines,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
$collection->append(
|
|
||||||
map Slic3r::ExtrusionPath->new(
|
|
||||||
polyline => $_,
|
|
||||||
role => ($is_bridge
|
|
||||||
? EXTR_ROLE_BRIDGE
|
|
||||||
: $is_solid
|
|
||||||
? (($surface->surface_type == S_TYPE_TOP) ? EXTR_ROLE_TOPSOLIDFILL : EXTR_ROLE_SOLIDFILL)
|
|
||||||
: EXTR_ROLE_FILL),
|
|
||||||
mm3_per_mm => $mm3_per_mm,
|
|
||||||
width => $flow->width,
|
|
||||||
height => ($is_bridge ? $flow->width : $h),
|
|
||||||
), @polylines,
|
|
||||||
);
|
|
||||||
push @fills_ordering_points, $polylines[0]->first_point;
|
push @fills_ordering_points, $polylines[0]->first_point;
|
||||||
}
|
}
|
||||||
|
|
||||||
# add thin fill regions
|
# add thin fill regions
|
||||||
foreach my $thin_fill (@{$layerm->thin_fills}) {
|
foreach my $thin_fill (@{$layerm->thin_fills}) {
|
||||||
push @fills, Slic3r::ExtrusionPath::Collection->new($thin_fill);
|
push @fills, Slic3r::ExtrusionPath::Collection->new($thin_fill->role, $thin_fill);
|
||||||
push @fills_ordering_points, $thin_fill->first_point;
|
push @fills_ordering_points, $thin_fill->first_point;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,10 +256,10 @@ sub _extrude_path {
|
|||||||
$acceleration = $self->config->first_layer_acceleration;
|
$acceleration = $self->config->first_layer_acceleration;
|
||||||
} elsif ($self->config->perimeter_acceleration && $path->is_perimeter) {
|
} elsif ($self->config->perimeter_acceleration && $path->is_perimeter) {
|
||||||
$acceleration = $self->config->perimeter_acceleration;
|
$acceleration = $self->config->perimeter_acceleration;
|
||||||
} elsif ($self->config->infill_acceleration && $path->is_fill) {
|
|
||||||
$acceleration = $self->config->infill_acceleration;
|
|
||||||
} elsif ($self->config->bridge_acceleration && $path->is_bridge) {
|
} elsif ($self->config->bridge_acceleration && $path->is_bridge) {
|
||||||
$acceleration = $self->config->bridge_acceleration;
|
$acceleration = $self->config->bridge_acceleration;
|
||||||
|
} elsif ($self->config->infill_acceleration && $path->is_infill) {
|
||||||
|
$acceleration = $self->config->infill_acceleration;
|
||||||
} else {
|
} else {
|
||||||
$acceleration = $self->config->default_acceleration;
|
$acceleration = $self->config->default_acceleration;
|
||||||
}
|
}
|
||||||
|
@ -454,7 +454,8 @@ sub build {
|
|||||||
complete_objects extruder_clearance_radius extruder_clearance_height
|
complete_objects extruder_clearance_radius extruder_clearance_height
|
||||||
gcode_comments output_filename_format
|
gcode_comments output_filename_format
|
||||||
post_process
|
post_process
|
||||||
perimeter_extruder infill_extruder support_material_extruder support_material_interface_extruder
|
perimeter_extruder infill_extruder solid_infill_extruder
|
||||||
|
support_material_extruder support_material_interface_extruder
|
||||||
ooze_prevention standby_temperature_delta
|
ooze_prevention standby_temperature_delta
|
||||||
interface_shells
|
interface_shells
|
||||||
extrusion_width first_layer_extrusion_width perimeter_extrusion_width
|
extrusion_width first_layer_extrusion_width perimeter_extrusion_width
|
||||||
@ -648,6 +649,7 @@ sub build {
|
|||||||
my $optgroup = $page->new_optgroup('Extruders');
|
my $optgroup = $page->new_optgroup('Extruders');
|
||||||
$optgroup->append_single_option_line('perimeter_extruder');
|
$optgroup->append_single_option_line('perimeter_extruder');
|
||||||
$optgroup->append_single_option_line('infill_extruder');
|
$optgroup->append_single_option_line('infill_extruder');
|
||||||
|
$optgroup->append_single_option_line('solid_infill_extruder');
|
||||||
$optgroup->append_single_option_line('support_material_extruder');
|
$optgroup->append_single_option_line('support_material_extruder');
|
||||||
$optgroup->append_single_option_line('support_material_interface_extruder');
|
$optgroup->append_single_option_line('support_material_interface_extruder');
|
||||||
}
|
}
|
||||||
|
@ -246,7 +246,7 @@ sub make_perimeters {
|
|||||||
my ($polynodes, $depth, $is_contour) = @_;
|
my ($polynodes, $depth, $is_contour) = @_;
|
||||||
|
|
||||||
# convert all polynodes to ExtrusionLoop objects
|
# convert all polynodes to ExtrusionLoop objects
|
||||||
my $collection = Slic3r::ExtrusionPath::Collection->new;
|
my $collection = Slic3r::ExtrusionPath::Collection->new(EXTR_ROLE_PERIMETER); # temporary collection
|
||||||
my @children = ();
|
my @children = ();
|
||||||
foreach my $polynode (@$polynodes) {
|
foreach my $polynode (@$polynodes) {
|
||||||
my $polygon = ($polynode->{outer} // $polynode->{hole})->clone;
|
my $polygon = ($polynode->{outer} // $polynode->{hole})->clone;
|
||||||
@ -303,7 +303,7 @@ sub make_perimeters {
|
|||||||
# (clone because the collection gets DESTROY'ed)
|
# (clone because the collection gets DESTROY'ed)
|
||||||
# We allow polyline reversal because Clipper may have randomly
|
# We allow polyline reversal because Clipper may have randomly
|
||||||
# reversed polylines during clipping.
|
# reversed polylines during clipping.
|
||||||
my $collection = Slic3r::ExtrusionPath::Collection->new(@paths);
|
my $collection = Slic3r::ExtrusionPath::Collection->new(EXTR_ROLE_PERIMETER, @paths); # temporary collection
|
||||||
@paths = map $_->clone, @{$collection->chained_path(0)};
|
@paths = map $_->clone, @{$collection->chained_path(0)};
|
||||||
} else {
|
} else {
|
||||||
push @paths, Slic3r::ExtrusionPath->new(
|
push @paths, Slic3r::ExtrusionPath->new(
|
||||||
|
@ -380,54 +380,87 @@ sub process_layer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# tweak region ordering to save toolchanges
|
# We now define a strategy for building perimeters and fills. The separation
|
||||||
my @region_ids = 0 .. ($self->print->region_count-1);
|
# between regions doesn't matter in terms of printing order, as we follow
|
||||||
if ($self->_gcodegen->writer->multiple_extruders) {
|
# another logic instead:
|
||||||
my $last_extruder_id = $self->_gcodegen->writer->extruder->id;
|
# - we group all extrusions by extruder so that we minimize toolchanges
|
||||||
my $best_region_id = first { $self->print->regions->[$_]->config->perimeter_extruder-1 == $last_extruder_id } @region_ids;
|
# - we start from the last used extruder
|
||||||
@region_ids = ($best_region_id, grep $_ != $best_region_id, @region_ids) if $best_region_id;
|
# - for each extruder, we group extrusions by island
|
||||||
|
# - for each island, we extrude perimeters first, unless user set the infill_first
|
||||||
|
# option
|
||||||
|
|
||||||
|
# group extrusions by extruder and then by island
|
||||||
|
my %by_extruder = (); # extruder_id => [ { perimeters => \@perimeters, infill => \@infill } ]
|
||||||
|
|
||||||
|
foreach my $region_id (0..($self->print->region_count-1)) {
|
||||||
|
my $layerm = $layer->regions->[$region_id] or next;
|
||||||
|
my $region = $self->print->get_region($region_id);
|
||||||
|
|
||||||
|
# process perimeters
|
||||||
|
{
|
||||||
|
my $extruder_id = $region->config->perimeter_extruder-1;
|
||||||
|
foreach my $perimeter (@{$layerm->perimeters}) {
|
||||||
|
# init by_extruder item only if we actually use the extruder
|
||||||
|
$by_extruder{$extruder_id} //= [];
|
||||||
|
|
||||||
|
# $perimeter is an ExtrusionLoop or ExtrusionPath object
|
||||||
|
for my $i (0 .. $#{$layer->slices}) {
|
||||||
|
if ($i == $#{$layer->slices}
|
||||||
|
|| $layer->slices->[$i]->contour->contains_point($perimeter->first_point)) {
|
||||||
|
$by_extruder{$extruder_id}[$i] //= { perimeters => {} };
|
||||||
|
$by_extruder{$extruder_id}[$i]{perimeters}{$region_id} //= [];
|
||||||
|
push @{ $by_extruder{$extruder_id}[$i]{perimeters}{$region_id} }, $perimeter;
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# process infill
|
||||||
|
{
|
||||||
|
foreach my $fill (@{$layerm->fills}) {
|
||||||
|
# init by_extruder item only if we actually use the extruder
|
||||||
|
my $extruder_id = $fill->[0]->is_solid_infill
|
||||||
|
? $region->config->solid_infill_extruder-1
|
||||||
|
: $region->config->infill_extruder-1;
|
||||||
|
|
||||||
|
$by_extruder{$extruder_id} //= [];
|
||||||
|
|
||||||
|
# $fill is an ExtrusionPath::Collection object
|
||||||
|
for my $i (0 .. $#{$layer->slices}) {
|
||||||
|
if ($i == $#{$layer->slices}
|
||||||
|
|| $layer->slices->[$i]->contour->contains_point($fill->first_point)) {
|
||||||
|
$by_extruder{$extruder_id}[$i] //= { infill => {} };
|
||||||
|
$by_extruder{$extruder_id}[$i]{infill}{$region_id} //= [];
|
||||||
|
push @{ $by_extruder{$extruder_id}[$i]{infill}{$region_id} }, $fill;
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach my $region_id (@region_ids) {
|
# tweak extruder ordering to save toolchanges
|
||||||
my $layerm = $layer->regions->[$region_id] or next;
|
my @extruders = sort keys %by_extruder;
|
||||||
my $region = $self->print->regions->[$region_id];
|
if (@extruders > 1) {
|
||||||
$self->_gcodegen->config->apply_region_config($region->config);
|
my $last_extruder_id = $self->_gcodegen->writer->extruder->id;
|
||||||
|
if (exists $by_extruder{$last_extruder_id}) {
|
||||||
# group extrusions by island
|
@extruders = (
|
||||||
my @perimeters_by_island = map [], 0..$#{$layer->slices}; # slice idx => @perimeters
|
$last_extruder_id,
|
||||||
my @infill_by_island = map [], 0..$#{$layer->slices}; # slice idx => @fills
|
grep $_ != $last_extruder_id, @extruders,
|
||||||
|
);
|
||||||
# NOTE: we assume $layer->slices was already ordered with chained_path()!
|
|
||||||
|
|
||||||
PERIMETER: foreach my $perimeter (@{$layerm->perimeters}) {
|
|
||||||
for my $i (0 .. $#{$layer->slices}-1) {
|
|
||||||
if ($layer->slices->[$i]->contour->contains_point($perimeter->first_point)) {
|
|
||||||
push @{ $perimeters_by_island[$i] }, $perimeter;
|
|
||||||
next PERIMETER;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
push @{ $perimeters_by_island[-1] }, $perimeter; # optimization
|
|
||||||
}
|
}
|
||||||
FILL: foreach my $fill (@{$layerm->fills}) {
|
}
|
||||||
for my $i (0 .. $#{$layer->slices}-1) {
|
|
||||||
if ($layer->slices->[$i]->contour->contains_point($fill->first_point)) {
|
foreach my $extruder_id (@extruders) {
|
||||||
push @{ $infill_by_island[$i] }, $fill;
|
$gcode .= $self->_gcodegen->set_extruder($extruder_id);
|
||||||
next FILL;
|
foreach my $island (@{ $by_extruder{$extruder_id} }) {
|
||||||
}
|
if ($self->print->config->infill_first) {
|
||||||
}
|
$gcode .= $self->_extrude_infill($island->{infill} // {});
|
||||||
push @{ $infill_by_island[-1] }, $fill; # optimization
|
$gcode .= $self->_extrude_perimeters($island->{perimeters} // {});
|
||||||
}
|
|
||||||
|
|
||||||
for my $i (0 .. $#{$layer->slices}) {
|
|
||||||
# give priority to infill if we were already using its extruder and it wouldn't
|
|
||||||
# be good for perimeters
|
|
||||||
if ($self->print->config->infill_first
|
|
||||||
|| ($self->_gcodegen->writer->multiple_extruders && $region->config->infill_extruder-1 == $self->_gcodegen->writer->extruder->id && $region->config->infill_extruder != $region->config->perimeter_extruder)) {
|
|
||||||
$gcode .= $self->_extrude_infill($infill_by_island[$i], $region);
|
|
||||||
$gcode .= $self->_extrude_perimeters($perimeters_by_island[$i], $region);
|
|
||||||
} else {
|
} else {
|
||||||
$gcode .= $self->_extrude_perimeters($perimeters_by_island[$i], $region);
|
$gcode .= $self->_extrude_perimeters($island->{perimeters} // {});
|
||||||
$gcode .= $self->_extrude_infill($infill_by_island[$i], $region);
|
$gcode .= $self->_extrude_infill($island->{infill} // {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -452,31 +485,30 @@ sub process_layer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub _extrude_perimeters {
|
sub _extrude_perimeters {
|
||||||
my $self = shift;
|
my ($self, $entities_by_region) = @_;
|
||||||
my ($island_perimeters, $region) = @_;
|
|
||||||
|
|
||||||
return "" if !@$island_perimeters;
|
|
||||||
|
|
||||||
my $gcode = "";
|
my $gcode = "";
|
||||||
$gcode .= $self->_gcodegen->set_extruder($region->config->perimeter_extruder-1);
|
foreach my $region_id (sort keys %$entities_by_region) {
|
||||||
$gcode .= $self->_gcodegen->extrude($_, 'perimeter') for @$island_perimeters;
|
$self->_gcodegen->config->apply_region_config($self->print->get_region($region_id)->config);
|
||||||
|
$gcode .= $self->_gcodegen->extrude($_, 'perimeter')
|
||||||
|
for @{ $entities_by_region->{$region_id} };
|
||||||
|
}
|
||||||
return $gcode;
|
return $gcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub _extrude_infill {
|
sub _extrude_infill {
|
||||||
my $self = shift;
|
my ($self, $entities_by_region) = @_;
|
||||||
my ($island_fills, $region) = @_;
|
|
||||||
|
|
||||||
return "" if !@$island_fills;
|
|
||||||
|
|
||||||
my $gcode = "";
|
my $gcode = "";
|
||||||
$gcode .= $self->_gcodegen->set_extruder($region->config->infill_extruder-1);
|
foreach my $region_id (sort keys %$entities_by_region) {
|
||||||
for my $fill (@$island_fills) {
|
$self->_gcodegen->config->apply_region_config($self->print->get_region($region_id)->config);
|
||||||
if ($fill->isa('Slic3r::ExtrusionPath::Collection')) {
|
for my $fill (@{ $entities_by_region->{$region_id} }) {
|
||||||
$gcode .= $self->_gcodegen->extrude($_, 'fill')
|
if ($fill->isa('Slic3r::ExtrusionPath::Collection')) {
|
||||||
for @{$fill->chained_path_from($self->_gcodegen->last_pos, 0)};
|
$gcode .= $self->_gcodegen->extrude($_, 'infill')
|
||||||
} else {
|
for @{$fill->chained_path_from($self->_gcodegen->last_pos, 0)};
|
||||||
$gcode .= $self->_gcodegen->extrude($fill, 'fill') ;
|
} else {
|
||||||
|
$gcode .= $self->_gcodegen->extrude($fill, 'infill') ;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $gcode;
|
return $gcode;
|
||||||
|
@ -1004,7 +1004,10 @@ sub combine_infill {
|
|||||||
next unless $every > 1 && $region->config->fill_density > 0;
|
next unless $every > 1 && $region->config->fill_density > 0;
|
||||||
|
|
||||||
# limit the number of combined layers to the maximum height allowed by this regions' nozzle
|
# limit the number of combined layers to the maximum height allowed by this regions' nozzle
|
||||||
my $nozzle_diameter = $self->print->config->get_at('nozzle_diameter', $region->config->infill_extruder-1);
|
my $nozzle_diameter = min(
|
||||||
|
$self->print->config->get_at('nozzle_diameter', $region->config->infill_extruder-1),
|
||||||
|
$self->print->config->get_at('nozzle_diameter', $region->config->solid_infill_extruder-1),
|
||||||
|
);
|
||||||
|
|
||||||
# define the combinations
|
# define the combinations
|
||||||
my %combine = (); # layer_idx => number of additional combined lower layers
|
my %combine = (); # layer_idx => number of additional combined lower layers
|
||||||
|
@ -262,7 +262,7 @@ sub contact_area {
|
|||||||
{
|
{
|
||||||
# get the average nozzle diameter used on this layer
|
# get the average nozzle diameter used on this layer
|
||||||
my @nozzle_diameters = map $self->print_config->get_at('nozzle_diameter', $_),
|
my @nozzle_diameters = map $self->print_config->get_at('nozzle_diameter', $_),
|
||||||
map { $_->config->perimeter_extruder-1, $_->config->infill_extruder-1 }
|
map { $_->config->perimeter_extruder-1, $_->config->infill_extruder-1, $_->config->solid_infill_extruder-1 }
|
||||||
@{$layer->regions};
|
@{$layer->regions};
|
||||||
my $nozzle_diameter = sum(@nozzle_diameters)/@nozzle_diameters;
|
my $nozzle_diameter = sum(@nozzle_diameters)/@nozzle_diameters;
|
||||||
|
|
||||||
|
@ -505,6 +505,7 @@ $j
|
|||||||
--perimeter-extruder
|
--perimeter-extruder
|
||||||
Extruder to use for perimeters (1+, default: $config->{perimeter_extruder})
|
Extruder to use for perimeters (1+, default: $config->{perimeter_extruder})
|
||||||
--infill-extruder Extruder to use for infill (1+, default: $config->{infill_extruder})
|
--infill-extruder Extruder to use for infill (1+, default: $config->{infill_extruder})
|
||||||
|
--solid-infill-extruder Extruder to use for solid infill (1+, default: $config->{solid_infill_extruder})
|
||||||
--support-material-extruder
|
--support-material-extruder
|
||||||
Extruder to use for support material (1+, default: $config->{support_material_extruder})
|
Extruder to use for support material (1+, default: $config->{support_material_extruder})
|
||||||
--support-material-interface-extruder
|
--support-material-interface-extruder
|
||||||
|
2
t/fill.t
2
t/fill.t
@ -146,6 +146,7 @@ sub scale_points (@) { map [scale $_->[X], scale $_->[Y]], @_ }
|
|||||||
|
|
||||||
{
|
{
|
||||||
my $collection = Slic3r::ExtrusionPath::Collection->new(
|
my $collection = Slic3r::ExtrusionPath::Collection->new(
|
||||||
|
EXTR_ROLE_PERIMETER,
|
||||||
map Slic3r::ExtrusionPath->new(polyline => $_, role => 0, mm3_per_mm => 1),
|
map Slic3r::ExtrusionPath->new(polyline => $_, role => 0, mm3_per_mm => 1),
|
||||||
Slic3r::Polyline->new([0,15], [0,18], [0,20]),
|
Slic3r::Polyline->new([0,15], [0,18], [0,20]),
|
||||||
Slic3r::Polyline->new([0,10], [0,8], [0,5]),
|
Slic3r::Polyline->new([0,10], [0,8], [0,5]),
|
||||||
@ -158,6 +159,7 @@ sub scale_points (@) { map [scale $_->[X], scale $_->[Y]], @_ }
|
|||||||
|
|
||||||
{
|
{
|
||||||
my $collection = Slic3r::ExtrusionPath::Collection->new(
|
my $collection = Slic3r::ExtrusionPath::Collection->new(
|
||||||
|
EXTR_ROLE_PERIMETER,
|
||||||
map Slic3r::ExtrusionPath->new(polyline => $_, role => 0, mm3_per_mm => 1),
|
map Slic3r::ExtrusionPath->new(polyline => $_, role => 0, mm3_per_mm => 1),
|
||||||
Slic3r::Polyline->new([15,0], [10,0], [4,0]),
|
Slic3r::Polyline->new([15,0], [10,0], [4,0]),
|
||||||
Slic3r::Polyline->new([10,5], [15,5], [20,5]),
|
Slic3r::Polyline->new([10,5], [15,5], [20,5]),
|
||||||
|
@ -64,9 +64,9 @@ use overload
|
|||||||
'fallback' => 1;
|
'fallback' => 1;
|
||||||
|
|
||||||
sub new {
|
sub new {
|
||||||
my ($class, @paths) = @_;
|
my ($class, $type, @paths) = @_;
|
||||||
|
|
||||||
my $self = $class->_new;
|
my $self = $class->_new($type);
|
||||||
$self->append(@paths);
|
$self->append(@paths);
|
||||||
return $self;
|
return $self;
|
||||||
}
|
}
|
||||||
|
@ -76,9 +76,18 @@ ExtrusionPath::is_perimeter() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ExtrusionPath::is_fill() const
|
ExtrusionPath::is_infill() const
|
||||||
{
|
{
|
||||||
return this->role == erInternalInfill
|
return this->role == erBridgeInfill
|
||||||
|
|| this->role == erInternalInfill
|
||||||
|
|| this->role == erSolidInfill
|
||||||
|
|| this->role == erTopSolidInfill;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ExtrusionPath::is_solid_infill() const
|
||||||
|
{
|
||||||
|
return this->role == erBridgeInfill
|
||||||
|| this->role == erSolidInfill
|
|| this->role == erSolidInfill
|
||||||
|| this->role == erTopSolidInfill;
|
|| this->role == erTopSolidInfill;
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,8 @@ class ExtrusionPath : public ExtrusionEntity
|
|||||||
void simplify(double tolerance);
|
void simplify(double tolerance);
|
||||||
double length() const;
|
double length() const;
|
||||||
bool is_perimeter() const;
|
bool is_perimeter() const;
|
||||||
bool is_fill() const;
|
bool is_infill() const;
|
||||||
|
bool is_solid_infill() const;
|
||||||
bool is_bridge() const;
|
bool is_bridge() const;
|
||||||
std::string gcode(Extruder* extruder, double e, double F,
|
std::string gcode(Extruder* extruder, double e, double F,
|
||||||
double xofs, double yofs, std::string extrusion_axis,
|
double xofs, double yofs, std::string extrusion_axis,
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
ExtrusionEntityCollection::ExtrusionEntityCollection(const ExtrusionEntityCollection& collection)
|
ExtrusionEntityCollection::ExtrusionEntityCollection(const ExtrusionEntityCollection& collection)
|
||||||
: no_sort(collection.no_sort), orig_indices(collection.orig_indices)
|
: no_sort(collection.no_sort), role(collection.role), orig_indices(collection.orig_indices)
|
||||||
{
|
{
|
||||||
this->entities.reserve(collection.entities.size());
|
this->entities.reserve(collection.entities.size());
|
||||||
for (ExtrusionEntitiesPtr::const_iterator it = collection.entities.begin(); it != collection.entities.end(); ++it)
|
for (ExtrusionEntitiesPtr::const_iterator it = collection.entities.begin(); it != collection.entities.end(); ++it)
|
||||||
@ -23,6 +23,7 @@ void
|
|||||||
ExtrusionEntityCollection::swap (ExtrusionEntityCollection &c)
|
ExtrusionEntityCollection::swap (ExtrusionEntityCollection &c)
|
||||||
{
|
{
|
||||||
std::swap(this->entities, c.entities);
|
std::swap(this->entities, c.entities);
|
||||||
|
std::swap(this->role, c.role);
|
||||||
std::swap(this->orig_indices, c.orig_indices);
|
std::swap(this->orig_indices, c.orig_indices);
|
||||||
std::swap(this->no_sort, c.no_sort);
|
std::swap(this->no_sort, c.no_sort);
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,9 @@ class ExtrusionEntityCollection : public ExtrusionEntity
|
|||||||
ExtrusionEntitiesPtr entities;
|
ExtrusionEntitiesPtr entities;
|
||||||
std::vector<size_t> orig_indices; // handy for XS
|
std::vector<size_t> orig_indices; // handy for XS
|
||||||
bool no_sort;
|
bool no_sort;
|
||||||
|
ExtrusionRole role;
|
||||||
ExtrusionEntityCollection(): no_sort(false) {};
|
ExtrusionEntityCollection(): no_sort(false) {};
|
||||||
|
ExtrusionEntityCollection(ExtrusionRole _role): no_sort(false), role(_role) {};
|
||||||
ExtrusionEntityCollection(const ExtrusionEntityCollection &collection);
|
ExtrusionEntityCollection(const ExtrusionEntityCollection &collection);
|
||||||
ExtrusionEntityCollection& operator= (const ExtrusionEntityCollection &other);
|
ExtrusionEntityCollection& operator= (const ExtrusionEntityCollection &other);
|
||||||
void swap (ExtrusionEntityCollection &c);
|
void swap (ExtrusionEntityCollection &c);
|
||||||
|
@ -46,9 +46,11 @@ class LayerRegion
|
|||||||
PolylineCollection unsupported_bridge_edges;
|
PolylineCollection unsupported_bridge_edges;
|
||||||
|
|
||||||
// ordered collection of extrusion paths/loops to build all perimeters
|
// ordered collection of extrusion paths/loops to build all perimeters
|
||||||
|
// (this collection contains both ExtrusionPath and ExtrusionLoop objects)
|
||||||
ExtrusionEntityCollection perimeters;
|
ExtrusionEntityCollection perimeters;
|
||||||
|
|
||||||
// ordered collection of extrusion paths to fill surfaces
|
// ordered collection of extrusion paths to fill surfaces
|
||||||
|
// (this collection contains only ExtrusionEntityCollection objects)
|
||||||
ExtrusionEntityCollection fills;
|
ExtrusionEntityCollection fills;
|
||||||
|
|
||||||
Flow flow(FlowRole role, bool bridge = false, double width = -1) const;
|
Flow flow(FlowRole role, bool bridge = false, double width = -1) const;
|
||||||
|
@ -301,6 +301,7 @@ Print::extruders() const
|
|||||||
FOREACH_REGION(this, region) {
|
FOREACH_REGION(this, region) {
|
||||||
extruders.insert((*region)->config.perimeter_extruder - 1);
|
extruders.insert((*region)->config.perimeter_extruder - 1);
|
||||||
extruders.insert((*region)->config.infill_extruder - 1);
|
extruders.insert((*region)->config.infill_extruder - 1);
|
||||||
|
extruders.insert((*region)->config.solid_infill_extruder - 1);
|
||||||
}
|
}
|
||||||
FOREACH_OBJECT(this, object) {
|
FOREACH_OBJECT(this, object) {
|
||||||
extruders.insert((*object)->config.support_material_extruder - 1);
|
extruders.insert((*object)->config.support_material_extruder - 1);
|
||||||
|
@ -694,6 +694,13 @@ PrintConfigDef::build_def() {
|
|||||||
Options["solid_infill_below_area"].cli = "solid-infill-below-area=f";
|
Options["solid_infill_below_area"].cli = "solid-infill-below-area=f";
|
||||||
Options["solid_infill_below_area"].min = 0;
|
Options["solid_infill_below_area"].min = 0;
|
||||||
|
|
||||||
|
Options["solid_infill_extruder"].type = coInt;
|
||||||
|
Options["solid_infill_extruder"].label = "Solid infill extruder";
|
||||||
|
Options["solid_infill_extruder"].category = "Extruders";
|
||||||
|
Options["solid_infill_extruder"].tooltip = "The extruder to use when printing solid infill.";
|
||||||
|
Options["solid_infill_extruder"].cli = "solid-infill-extruder=i";
|
||||||
|
Options["solid_infill_extruder"].min = 1;
|
||||||
|
|
||||||
Options["solid_infill_every_layers"].type = coInt;
|
Options["solid_infill_every_layers"].type = coInt;
|
||||||
Options["solid_infill_every_layers"].label = "Solid infill every";
|
Options["solid_infill_every_layers"].label = "Solid infill every";
|
||||||
Options["solid_infill_every_layers"].category = "Infill";
|
Options["solid_infill_every_layers"].category = "Infill";
|
||||||
|
@ -93,6 +93,10 @@ class DynamicPrintConfig : public DynamicConfig
|
|||||||
this->option("support_material_interface_extruder", true)->setInt(extruder);
|
this->option("support_material_interface_extruder", true)->setInt(extruder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this->has("solid_infill_extruder") && this->has("infill_extruder"))
|
||||||
|
this->option("solid_infill_extruder", true)->setInt(this->option("infill_extruder")->getInt());
|
||||||
|
|
||||||
if (this->has("spiral_vase") && this->opt<ConfigOptionBool>("spiral_vase", true)->value) {
|
if (this->has("spiral_vase") && this->opt<ConfigOptionBool>("spiral_vase", true)->value) {
|
||||||
{
|
{
|
||||||
// this should be actually done only on the spiral layers instead of all
|
// this should be actually done only on the spiral layers instead of all
|
||||||
@ -225,6 +229,7 @@ class PrintRegionConfig : public virtual StaticPrintConfig
|
|||||||
ConfigOptionInt perimeters;
|
ConfigOptionInt perimeters;
|
||||||
ConfigOptionFloatOrPercent small_perimeter_speed;
|
ConfigOptionFloatOrPercent small_perimeter_speed;
|
||||||
ConfigOptionFloat solid_infill_below_area;
|
ConfigOptionFloat solid_infill_below_area;
|
||||||
|
ConfigOptionInt solid_infill_extruder;
|
||||||
ConfigOptionFloatOrPercent solid_infill_extrusion_width;
|
ConfigOptionFloatOrPercent solid_infill_extrusion_width;
|
||||||
ConfigOptionInt solid_infill_every_layers;
|
ConfigOptionInt solid_infill_every_layers;
|
||||||
ConfigOptionFloatOrPercent solid_infill_speed;
|
ConfigOptionFloatOrPercent solid_infill_speed;
|
||||||
@ -259,6 +264,7 @@ class PrintRegionConfig : public virtual StaticPrintConfig
|
|||||||
this->perimeter_extrusion_width.percent = false;
|
this->perimeter_extrusion_width.percent = false;
|
||||||
this->perimeter_speed.value = 30;
|
this->perimeter_speed.value = 30;
|
||||||
this->perimeters.value = 3;
|
this->perimeters.value = 3;
|
||||||
|
this->solid_infill_extruder.value = 1;
|
||||||
this->small_perimeter_speed.value = 30;
|
this->small_perimeter_speed.value = 30;
|
||||||
this->small_perimeter_speed.percent = false;
|
this->small_perimeter_speed.percent = false;
|
||||||
this->solid_infill_below_area.value = 70;
|
this->solid_infill_below_area.value = 70;
|
||||||
@ -299,6 +305,7 @@ class PrintRegionConfig : public virtual StaticPrintConfig
|
|||||||
if (opt_key == "perimeters") return &this->perimeters;
|
if (opt_key == "perimeters") return &this->perimeters;
|
||||||
if (opt_key == "small_perimeter_speed") return &this->small_perimeter_speed;
|
if (opt_key == "small_perimeter_speed") return &this->small_perimeter_speed;
|
||||||
if (opt_key == "solid_infill_below_area") return &this->solid_infill_below_area;
|
if (opt_key == "solid_infill_below_area") return &this->solid_infill_below_area;
|
||||||
|
if (opt_key == "solid_infill_extruder") return &this->solid_infill_extruder;
|
||||||
if (opt_key == "solid_infill_extrusion_width") return &this->solid_infill_extrusion_width;
|
if (opt_key == "solid_infill_extrusion_width") return &this->solid_infill_extrusion_width;
|
||||||
if (opt_key == "solid_infill_every_layers") return &this->solid_infill_every_layers;
|
if (opt_key == "solid_infill_every_layers") return &this->solid_infill_every_layers;
|
||||||
if (opt_key == "solid_infill_speed") return &this->solid_infill_speed;
|
if (opt_key == "solid_infill_speed") return &this->solid_infill_speed;
|
||||||
|
@ -255,6 +255,7 @@ PrintObject::invalidate_state_by_config_options(const std::vector<t_config_optio
|
|||||||
|| *opt_key == "top_solid_layers"
|
|| *opt_key == "top_solid_layers"
|
||||||
|| *opt_key == "solid_infill_below_area"
|
|| *opt_key == "solid_infill_below_area"
|
||||||
|| *opt_key == "infill_extruder"
|
|| *opt_key == "infill_extruder"
|
||||||
|
|| *opt_key == "solid_infill_extruder"
|
||||||
|| *opt_key == "infill_extrusion_width") {
|
|| *opt_key == "infill_extrusion_width") {
|
||||||
steps.insert(posPrepareInfill);
|
steps.insert(posPrepareInfill);
|
||||||
} else if (*opt_key == "external_fill_pattern"
|
} else if (*opt_key == "external_fill_pattern"
|
||||||
|
@ -53,8 +53,10 @@ PrintRegion::flow(FlowRole role, double layer_height, bool bridge, bool first_la
|
|||||||
size_t extruder; // 1-based
|
size_t extruder; // 1-based
|
||||||
if (role == frPerimeter || role == frExternalPerimeter) {
|
if (role == frPerimeter || role == frExternalPerimeter) {
|
||||||
extruder = this->config.perimeter_extruder;
|
extruder = this->config.perimeter_extruder;
|
||||||
} else if (role == frInfill || role == frSolidInfill || role == frTopSolidInfill) {
|
} else if (role == frInfill) {
|
||||||
extruder = this->config.infill_extruder;
|
extruder = this->config.infill_extruder;
|
||||||
|
} else if (role == frSolidInfill || role == frTopSolidInfill) {
|
||||||
|
extruder = this->config.solid_infill_extruder;
|
||||||
} else {
|
} else {
|
||||||
CONFESS("Unknown role $role");
|
CONFESS("Unknown role $role");
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,10 @@ my $loop = Slic3r::ExtrusionLoop->new_from_paths(
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
my $collection = Slic3r::ExtrusionPath::Collection->new($path);
|
my $collection = Slic3r::ExtrusionPath::Collection->new(
|
||||||
|
Slic3r::ExtrusionPath::EXTR_ROLE_FILL,
|
||||||
|
$path,
|
||||||
|
);
|
||||||
isa_ok $collection, 'Slic3r::ExtrusionPath::Collection', 'collection object with items in constructor';
|
isa_ok $collection, 'Slic3r::ExtrusionPath::Collection', 'collection object with items in constructor';
|
||||||
ok !$collection->no_sort, 'no_sort is false by default';
|
ok !$collection->no_sort, 'no_sort is false by default';
|
||||||
|
|
||||||
@ -55,6 +58,7 @@ is scalar(@{$collection->[1]}), 1, 'appended collection was duplicated';
|
|||||||
|
|
||||||
{
|
{
|
||||||
my $collection = Slic3r::ExtrusionPath::Collection->new(
|
my $collection = Slic3r::ExtrusionPath::Collection->new(
|
||||||
|
Slic3r::ExtrusionPath::EXTR_ROLE_FILL,
|
||||||
map Slic3r::ExtrusionPath->new(polyline => $_, role => 0, mm3_per_mm => 1),
|
map Slic3r::ExtrusionPath->new(polyline => $_, role => 0, mm3_per_mm => 1),
|
||||||
Slic3r::Polyline->new([0,15], [0,18], [0,20]),
|
Slic3r::Polyline->new([0,15], [0,18], [0,20]),
|
||||||
Slic3r::Polyline->new([0,10], [0,8], [0,5]),
|
Slic3r::Polyline->new([0,10], [0,8], [0,5]),
|
||||||
@ -71,6 +75,7 @@ is scalar(@{$collection->[1]}), 1, 'appended collection was duplicated';
|
|||||||
|
|
||||||
{
|
{
|
||||||
my $collection = Slic3r::ExtrusionPath::Collection->new(
|
my $collection = Slic3r::ExtrusionPath::Collection->new(
|
||||||
|
Slic3r::ExtrusionPath::EXTR_ROLE_FILL,
|
||||||
map Slic3r::ExtrusionPath->new(polyline => $_, role => 0, mm3_per_mm => 1),
|
map Slic3r::ExtrusionPath->new(polyline => $_, role => 0, mm3_per_mm => 1),
|
||||||
Slic3r::Polyline->new([15,0], [10,0], [4,0]),
|
Slic3r::Polyline->new([15,0], [10,0], [4,0]),
|
||||||
Slic3r::Polyline->new([10,5], [15,5], [20,5]),
|
Slic3r::Polyline->new([10,5], [15,5], [20,5]),
|
||||||
|
@ -4,7 +4,7 @@ use strict;
|
|||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
use Slic3r::XS;
|
use Slic3r::XS;
|
||||||
use Test::More tests => 107;
|
use Test::More tests => 108;
|
||||||
|
|
||||||
foreach my $config (Slic3r::Config->new, Slic3r::Config::Full->new) {
|
foreach my $config (Slic3r::Config->new, Slic3r::Config::Full->new) {
|
||||||
$config->set('layer_height', 0.3);
|
$config->set('layer_height', 0.3);
|
||||||
@ -182,6 +182,13 @@ foreach my $config (Slic3r::Config->new, Slic3r::Config::Full->new) {
|
|||||||
is $config->get('perimeter_extruder'), 3, 'defined extruder is not overwritten by default extruder';
|
is $config->get('perimeter_extruder'), 3, 'defined extruder is not overwritten by default extruder';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $config = Slic3r::Config->new;
|
||||||
|
$config->set('infill_extruder', 2);
|
||||||
|
$config->normalize;
|
||||||
|
is $config->get('solid_infill_extruder'), 2, 'undefined solid infill extruder is populated with infill extruder';
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
my $config = Slic3r::Config->new;
|
my $config = Slic3r::Config->new;
|
||||||
$config->set('spiral_vase', 1);
|
$config->set('spiral_vase', 1);
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
%}
|
%}
|
||||||
|
|
||||||
%name{Slic3r::ExtrusionPath::Collection} class ExtrusionEntityCollection {
|
%name{Slic3r::ExtrusionPath::Collection} class ExtrusionEntityCollection {
|
||||||
%name{_new} ExtrusionEntityCollection();
|
%name{_new} ExtrusionEntityCollection(ExtrusionRole role);
|
||||||
void reverse();
|
void reverse();
|
||||||
void clear()
|
void clear()
|
||||||
%code{% THIS->entities.clear(); %};
|
%code{% THIS->entities.clear(); %};
|
||||||
|
@ -23,7 +23,8 @@
|
|||||||
void simplify(double tolerance);
|
void simplify(double tolerance);
|
||||||
double length();
|
double length();
|
||||||
bool is_perimeter();
|
bool is_perimeter();
|
||||||
bool is_fill();
|
bool is_infill();
|
||||||
|
bool is_solid_infill();
|
||||||
bool is_bridge();
|
bool is_bridge();
|
||||||
std::string gcode(Extruder* extruder, double e, double F,
|
std::string gcode(Extruder* extruder, double e, double F,
|
||||||
double xofs, double yofs, std::string extrusion_axis,
|
double xofs, double yofs, std::string extrusion_axis,
|
||||||
|
Loading…
Reference in New Issue
Block a user