From e79aa2e81c3087d44c46d0fcb65cd81a42f0585d Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Wed, 17 Dec 2014 00:34:00 +0100 Subject: [PATCH] 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 --- README.md | 1 + lib/Slic3r/Fill.pm | 36 ++-- lib/Slic3r/GCode.pm | 4 +- lib/Slic3r/GUI/Tab.pm | 4 +- lib/Slic3r/Layer/Region.pm | 4 +- lib/Slic3r/Print/GCode.pm | 154 +++++++++++------- lib/Slic3r/Print/Object.pm | 5 +- lib/Slic3r/Print/SupportMaterial.pm | 2 +- slic3r.pl | 1 + t/fill.t | 2 + xs/lib/Slic3r/XS.pm | 4 +- xs/src/libslic3r/ExtrusionEntity.cpp | 13 +- xs/src/libslic3r/ExtrusionEntity.hpp | 3 +- .../libslic3r/ExtrusionEntityCollection.cpp | 3 +- .../libslic3r/ExtrusionEntityCollection.hpp | 2 + xs/src/libslic3r/Layer.hpp | 2 + xs/src/libslic3r/Print.cpp | 1 + xs/src/libslic3r/PrintConfig.cpp | 7 + xs/src/libslic3r/PrintConfig.hpp | 7 + xs/src/libslic3r/PrintObject.cpp | 1 + xs/src/libslic3r/PrintRegion.cpp | 4 +- xs/t/12_extrusionpathcollection.t | 7 +- xs/t/15_config.t | 9 +- xs/xsp/ExtrusionEntityCollection.xsp | 2 +- xs/xsp/ExtrusionPath.xsp | 3 +- 25 files changed, 186 insertions(+), 95 deletions(-) diff --git a/README.md b/README.md index 4e35d5572..fe8c267d6 100644 --- a/README.md +++ b/README.md @@ -353,6 +353,7 @@ The author of the Silk icon set is Mark James. --perimeter-extruder Extruder to use for perimeters (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 Extruder to use for support material (1+, default: 1) --support-material-interface-extruder diff --git a/lib/Slic3r/Fill.pm b/lib/Slic3r/Fill.pm index 82c2ec6cc..4547a846b 100644 --- a/lib/Slic3r/Fill.pm +++ b/lib/Slic3r/Fill.pm @@ -225,28 +225,32 @@ sub make_fill { my $mm3_per_mm = $flow->mm3_per_mm; # 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; } # add thin fill regions 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; } diff --git a/lib/Slic3r/GCode.pm b/lib/Slic3r/GCode.pm index 662d95a86..9dc4e29bd 100644 --- a/lib/Slic3r/GCode.pm +++ b/lib/Slic3r/GCode.pm @@ -256,10 +256,10 @@ sub _extrude_path { $acceleration = $self->config->first_layer_acceleration; } elsif ($self->config->perimeter_acceleration && $path->is_perimeter) { $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) { $acceleration = $self->config->bridge_acceleration; + } elsif ($self->config->infill_acceleration && $path->is_infill) { + $acceleration = $self->config->infill_acceleration; } else { $acceleration = $self->config->default_acceleration; } diff --git a/lib/Slic3r/GUI/Tab.pm b/lib/Slic3r/GUI/Tab.pm index ecb476fd5..ad589e2b5 100644 --- a/lib/Slic3r/GUI/Tab.pm +++ b/lib/Slic3r/GUI/Tab.pm @@ -454,7 +454,8 @@ sub build { complete_objects extruder_clearance_radius extruder_clearance_height gcode_comments output_filename_format 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 interface_shells extrusion_width first_layer_extrusion_width perimeter_extrusion_width @@ -648,6 +649,7 @@ sub build { my $optgroup = $page->new_optgroup('Extruders'); $optgroup->append_single_option_line('perimeter_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_interface_extruder'); } diff --git a/lib/Slic3r/Layer/Region.pm b/lib/Slic3r/Layer/Region.pm index fbc665df3..bc09f77ca 100644 --- a/lib/Slic3r/Layer/Region.pm +++ b/lib/Slic3r/Layer/Region.pm @@ -246,7 +246,7 @@ sub make_perimeters { my ($polynodes, $depth, $is_contour) = @_; # 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 = (); foreach my $polynode (@$polynodes) { my $polygon = ($polynode->{outer} // $polynode->{hole})->clone; @@ -303,7 +303,7 @@ sub make_perimeters { # (clone because the collection gets DESTROY'ed) # We allow polyline reversal because Clipper may have randomly # 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)}; } else { push @paths, Slic3r::ExtrusionPath->new( diff --git a/lib/Slic3r/Print/GCode.pm b/lib/Slic3r/Print/GCode.pm index ca572fc72..7417c48ec 100644 --- a/lib/Slic3r/Print/GCode.pm +++ b/lib/Slic3r/Print/GCode.pm @@ -380,54 +380,87 @@ sub process_layer { } } - # tweak region ordering to save toolchanges - my @region_ids = 0 .. ($self->print->region_count-1); - if ($self->_gcodegen->writer->multiple_extruders) { - my $last_extruder_id = $self->_gcodegen->writer->extruder->id; - my $best_region_id = first { $self->print->regions->[$_]->config->perimeter_extruder-1 == $last_extruder_id } @region_ids; - @region_ids = ($best_region_id, grep $_ != $best_region_id, @region_ids) if $best_region_id; + # We now define a strategy for building perimeters and fills. The separation + # between regions doesn't matter in terms of printing order, as we follow + # another logic instead: + # - we group all extrusions by extruder so that we minimize toolchanges + # - we start from the last used extruder + # - 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) { - my $layerm = $layer->regions->[$region_id] or next; - my $region = $self->print->regions->[$region_id]; - $self->_gcodegen->config->apply_region_config($region->config); - - # group extrusions by island - my @perimeters_by_island = map [], 0..$#{$layer->slices}; # slice idx => @perimeters - my @infill_by_island = map [], 0..$#{$layer->slices}; # slice idx => @fills - - # 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 + # tweak extruder ordering to save toolchanges + my @extruders = sort keys %by_extruder; + if (@extruders > 1) { + my $last_extruder_id = $self->_gcodegen->writer->extruder->id; + if (exists $by_extruder{$last_extruder_id}) { + @extruders = ( + $last_extruder_id, + grep $_ != $last_extruder_id, @extruders, + ); } - FILL: foreach my $fill (@{$layerm->fills}) { - for my $i (0 .. $#{$layer->slices}-1) { - if ($layer->slices->[$i]->contour->contains_point($fill->first_point)) { - push @{ $infill_by_island[$i] }, $fill; - next FILL; - } - } - push @{ $infill_by_island[-1] }, $fill; # optimization - } - - 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); + } + + foreach my $extruder_id (@extruders) { + $gcode .= $self->_gcodegen->set_extruder($extruder_id); + foreach my $island (@{ $by_extruder{$extruder_id} }) { + if ($self->print->config->infill_first) { + $gcode .= $self->_extrude_infill($island->{infill} // {}); + $gcode .= $self->_extrude_perimeters($island->{perimeters} // {}); } else { - $gcode .= $self->_extrude_perimeters($perimeters_by_island[$i], $region); - $gcode .= $self->_extrude_infill($infill_by_island[$i], $region); + $gcode .= $self->_extrude_perimeters($island->{perimeters} // {}); + $gcode .= $self->_extrude_infill($island->{infill} // {}); } } } @@ -452,31 +485,30 @@ sub process_layer { } sub _extrude_perimeters { - my $self = shift; - my ($island_perimeters, $region) = @_; - - return "" if !@$island_perimeters; + my ($self, $entities_by_region) = @_; my $gcode = ""; - $gcode .= $self->_gcodegen->set_extruder($region->config->perimeter_extruder-1); - $gcode .= $self->_gcodegen->extrude($_, 'perimeter') for @$island_perimeters; + foreach my $region_id (sort keys %$entities_by_region) { + $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; } sub _extrude_infill { - my $self = shift; - my ($island_fills, $region) = @_; - - return "" if !@$island_fills; + my ($self, $entities_by_region) = @_; my $gcode = ""; - $gcode .= $self->_gcodegen->set_extruder($region->config->infill_extruder-1); - for my $fill (@$island_fills) { - if ($fill->isa('Slic3r::ExtrusionPath::Collection')) { - $gcode .= $self->_gcodegen->extrude($_, 'fill') - for @{$fill->chained_path_from($self->_gcodegen->last_pos, 0)}; - } else { - $gcode .= $self->_gcodegen->extrude($fill, 'fill') ; + foreach my $region_id (sort keys %$entities_by_region) { + $self->_gcodegen->config->apply_region_config($self->print->get_region($region_id)->config); + for my $fill (@{ $entities_by_region->{$region_id} }) { + if ($fill->isa('Slic3r::ExtrusionPath::Collection')) { + $gcode .= $self->_gcodegen->extrude($_, 'infill') + for @{$fill->chained_path_from($self->_gcodegen->last_pos, 0)}; + } else { + $gcode .= $self->_gcodegen->extrude($fill, 'infill') ; + } } } return $gcode; diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index 166f18792..be819fefb 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -1004,7 +1004,10 @@ sub combine_infill { next unless $every > 1 && $region->config->fill_density > 0; # 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 my %combine = (); # layer_idx => number of additional combined lower layers diff --git a/lib/Slic3r/Print/SupportMaterial.pm b/lib/Slic3r/Print/SupportMaterial.pm index 01df21a55..5771fcc66 100644 --- a/lib/Slic3r/Print/SupportMaterial.pm +++ b/lib/Slic3r/Print/SupportMaterial.pm @@ -262,7 +262,7 @@ sub contact_area { { # get the average nozzle diameter used on this layer 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}; my $nozzle_diameter = sum(@nozzle_diameters)/@nozzle_diameters; diff --git a/slic3r.pl b/slic3r.pl index 70e109215..3568f92e3 100755 --- a/slic3r.pl +++ b/slic3r.pl @@ -505,6 +505,7 @@ $j --perimeter-extruder Extruder to use for perimeters (1+, default: $config->{perimeter_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 Extruder to use for support material (1+, default: $config->{support_material_extruder}) --support-material-interface-extruder diff --git a/t/fill.t b/t/fill.t index 24370b660..15f693a66 100644 --- a/t/fill.t +++ b/t/fill.t @@ -146,6 +146,7 @@ sub scale_points (@) { map [scale $_->[X], scale $_->[Y]], @_ } { my $collection = Slic3r::ExtrusionPath::Collection->new( + EXTR_ROLE_PERIMETER, map Slic3r::ExtrusionPath->new(polyline => $_, role => 0, mm3_per_mm => 1), Slic3r::Polyline->new([0,15], [0,18], [0,20]), 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( + EXTR_ROLE_PERIMETER, map Slic3r::ExtrusionPath->new(polyline => $_, role => 0, mm3_per_mm => 1), Slic3r::Polyline->new([15,0], [10,0], [4,0]), Slic3r::Polyline->new([10,5], [15,5], [20,5]), diff --git a/xs/lib/Slic3r/XS.pm b/xs/lib/Slic3r/XS.pm index 9ac0b35e9..08bb625cb 100644 --- a/xs/lib/Slic3r/XS.pm +++ b/xs/lib/Slic3r/XS.pm @@ -64,9 +64,9 @@ use overload 'fallback' => 1; sub new { - my ($class, @paths) = @_; + my ($class, $type, @paths) = @_; - my $self = $class->_new; + my $self = $class->_new($type); $self->append(@paths); return $self; } diff --git a/xs/src/libslic3r/ExtrusionEntity.cpp b/xs/src/libslic3r/ExtrusionEntity.cpp index 1bc5b4b24..7901317a3 100644 --- a/xs/src/libslic3r/ExtrusionEntity.cpp +++ b/xs/src/libslic3r/ExtrusionEntity.cpp @@ -76,9 +76,18 @@ ExtrusionPath::is_perimeter() const } 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 == erTopSolidInfill; } diff --git a/xs/src/libslic3r/ExtrusionEntity.hpp b/xs/src/libslic3r/ExtrusionEntity.hpp index aad36cb3d..da7658b76 100644 --- a/xs/src/libslic3r/ExtrusionEntity.hpp +++ b/xs/src/libslic3r/ExtrusionEntity.hpp @@ -64,7 +64,8 @@ class ExtrusionPath : public ExtrusionEntity void simplify(double tolerance); double length() const; bool is_perimeter() const; - bool is_fill() const; + bool is_infill() const; + bool is_solid_infill() const; bool is_bridge() const; std::string gcode(Extruder* extruder, double e, double F, double xofs, double yofs, std::string extrusion_axis, diff --git a/xs/src/libslic3r/ExtrusionEntityCollection.cpp b/xs/src/libslic3r/ExtrusionEntityCollection.cpp index a958e53cf..89748bc86 100644 --- a/xs/src/libslic3r/ExtrusionEntityCollection.cpp +++ b/xs/src/libslic3r/ExtrusionEntityCollection.cpp @@ -5,7 +5,7 @@ namespace Slic3r { 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()); for (ExtrusionEntitiesPtr::const_iterator it = collection.entities.begin(); it != collection.entities.end(); ++it) @@ -23,6 +23,7 @@ void ExtrusionEntityCollection::swap (ExtrusionEntityCollection &c) { std::swap(this->entities, c.entities); + std::swap(this->role, c.role); std::swap(this->orig_indices, c.orig_indices); std::swap(this->no_sort, c.no_sort); } diff --git a/xs/src/libslic3r/ExtrusionEntityCollection.hpp b/xs/src/libslic3r/ExtrusionEntityCollection.hpp index bc660611b..a72563f47 100644 --- a/xs/src/libslic3r/ExtrusionEntityCollection.hpp +++ b/xs/src/libslic3r/ExtrusionEntityCollection.hpp @@ -13,7 +13,9 @@ class ExtrusionEntityCollection : public ExtrusionEntity ExtrusionEntitiesPtr entities; std::vector orig_indices; // handy for XS bool no_sort; + ExtrusionRole role; ExtrusionEntityCollection(): no_sort(false) {}; + ExtrusionEntityCollection(ExtrusionRole _role): no_sort(false), role(_role) {}; ExtrusionEntityCollection(const ExtrusionEntityCollection &collection); ExtrusionEntityCollection& operator= (const ExtrusionEntityCollection &other); void swap (ExtrusionEntityCollection &c); diff --git a/xs/src/libslic3r/Layer.hpp b/xs/src/libslic3r/Layer.hpp index ff8cca1d9..115a728e0 100644 --- a/xs/src/libslic3r/Layer.hpp +++ b/xs/src/libslic3r/Layer.hpp @@ -46,9 +46,11 @@ class LayerRegion PolylineCollection unsupported_bridge_edges; // ordered collection of extrusion paths/loops to build all perimeters + // (this collection contains both ExtrusionPath and ExtrusionLoop objects) ExtrusionEntityCollection perimeters; // ordered collection of extrusion paths to fill surfaces + // (this collection contains only ExtrusionEntityCollection objects) ExtrusionEntityCollection fills; Flow flow(FlowRole role, bool bridge = false, double width = -1) const; diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index 6edd32609..9d834c605 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -301,6 +301,7 @@ Print::extruders() const FOREACH_REGION(this, region) { extruders.insert((*region)->config.perimeter_extruder - 1); extruders.insert((*region)->config.infill_extruder - 1); + extruders.insert((*region)->config.solid_infill_extruder - 1); } FOREACH_OBJECT(this, object) { extruders.insert((*object)->config.support_material_extruder - 1); diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index 8e9720b76..649c941e9 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -694,6 +694,13 @@ PrintConfigDef::build_def() { Options["solid_infill_below_area"].cli = "solid-infill-below-area=f"; 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"].label = "Solid infill every"; Options["solid_infill_every_layers"].category = "Infill"; diff --git a/xs/src/libslic3r/PrintConfig.hpp b/xs/src/libslic3r/PrintConfig.hpp index 447948a26..48235c7d1 100644 --- a/xs/src/libslic3r/PrintConfig.hpp +++ b/xs/src/libslic3r/PrintConfig.hpp @@ -93,6 +93,10 @@ class DynamicPrintConfig : public DynamicConfig 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("spiral_vase", true)->value) { { // this should be actually done only on the spiral layers instead of all @@ -225,6 +229,7 @@ class PrintRegionConfig : public virtual StaticPrintConfig ConfigOptionInt perimeters; ConfigOptionFloatOrPercent small_perimeter_speed; ConfigOptionFloat solid_infill_below_area; + ConfigOptionInt solid_infill_extruder; ConfigOptionFloatOrPercent solid_infill_extrusion_width; ConfigOptionInt solid_infill_every_layers; ConfigOptionFloatOrPercent solid_infill_speed; @@ -259,6 +264,7 @@ class PrintRegionConfig : public virtual StaticPrintConfig this->perimeter_extrusion_width.percent = false; this->perimeter_speed.value = 30; this->perimeters.value = 3; + this->solid_infill_extruder.value = 1; this->small_perimeter_speed.value = 30; this->small_perimeter_speed.percent = false; 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 == "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_extruder") return &this->solid_infill_extruder; 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_speed") return &this->solid_infill_speed; diff --git a/xs/src/libslic3r/PrintObject.cpp b/xs/src/libslic3r/PrintObject.cpp index 0da9d589b..da7e25a48 100644 --- a/xs/src/libslic3r/PrintObject.cpp +++ b/xs/src/libslic3r/PrintObject.cpp @@ -255,6 +255,7 @@ PrintObject::invalidate_state_by_config_options(const std::vectorconfig.perimeter_extruder; - } else if (role == frInfill || role == frSolidInfill || role == frTopSolidInfill) { + } else if (role == frInfill) { extruder = this->config.infill_extruder; + } else if (role == frSolidInfill || role == frTopSolidInfill) { + extruder = this->config.solid_infill_extruder; } else { CONFESS("Unknown role $role"); } diff --git a/xs/t/12_extrusionpathcollection.t b/xs/t/12_extrusionpathcollection.t index 6933f965a..7349ca941 100644 --- a/xs/t/12_extrusionpathcollection.t +++ b/xs/t/12_extrusionpathcollection.t @@ -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'; 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( + Slic3r::ExtrusionPath::EXTR_ROLE_FILL, map Slic3r::ExtrusionPath->new(polyline => $_, role => 0, mm3_per_mm => 1), Slic3r::Polyline->new([0,15], [0,18], [0,20]), 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( + Slic3r::ExtrusionPath::EXTR_ROLE_FILL, map Slic3r::ExtrusionPath->new(polyline => $_, role => 0, mm3_per_mm => 1), Slic3r::Polyline->new([15,0], [10,0], [4,0]), Slic3r::Polyline->new([10,5], [15,5], [20,5]), diff --git a/xs/t/15_config.t b/xs/t/15_config.t index cd4dc2654..e051d9a86 100644 --- a/xs/t/15_config.t +++ b/xs/t/15_config.t @@ -4,7 +4,7 @@ use strict; use warnings; use Slic3r::XS; -use Test::More tests => 107; +use Test::More tests => 108; foreach my $config (Slic3r::Config->new, Slic3r::Config::Full->new) { $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'; } +{ + 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; $config->set('spiral_vase', 1); diff --git a/xs/xsp/ExtrusionEntityCollection.xsp b/xs/xsp/ExtrusionEntityCollection.xsp index fa1d26eed..290bcea50 100644 --- a/xs/xsp/ExtrusionEntityCollection.xsp +++ b/xs/xsp/ExtrusionEntityCollection.xsp @@ -6,7 +6,7 @@ %} %name{Slic3r::ExtrusionPath::Collection} class ExtrusionEntityCollection { - %name{_new} ExtrusionEntityCollection(); + %name{_new} ExtrusionEntityCollection(ExtrusionRole role); void reverse(); void clear() %code{% THIS->entities.clear(); %}; diff --git a/xs/xsp/ExtrusionPath.xsp b/xs/xsp/ExtrusionPath.xsp index d3a48ac24..4fbaea2d6 100644 --- a/xs/xsp/ExtrusionPath.xsp +++ b/xs/xsp/ExtrusionPath.xsp @@ -23,7 +23,8 @@ void simplify(double tolerance); double length(); bool is_perimeter(); - bool is_fill(); + bool is_infill(); + bool is_solid_infill(); bool is_bridge(); std::string gcode(Extruder* extruder, double e, double F, double xofs, double yofs, std::string extrusion_axis,