From cac79c057555d9c3baa497ec319db1869dcf2fd3 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Sat, 9 Feb 2013 23:36:32 +0100 Subject: [PATCH] New option to only infill where strictly needed for supporting ceilings --- README.markdown | 2 ++ lib/Slic3r/Config.pm | 7 +++++ lib/Slic3r/GUI/Tab.pm | 3 +- lib/Slic3r/Layer/Region.pm | 9 +++++- lib/Slic3r/Print.pm | 1 + lib/Slic3r/Print/Object.pm | 61 ++++++++++++++++++++++++++++++++++---- slic3r.pl | 2 ++ 7 files changed, 77 insertions(+), 8 deletions(-) diff --git a/README.markdown b/README.markdown index 21498b0f5..76c1845d3 100644 --- a/README.markdown +++ b/README.markdown @@ -197,6 +197,8 @@ The author of the Silk icon set is Mark James. --solid-infill-below-area Force solid infill when a region has a smaller area than this threshold (mm^2, default: 70) + --infill-only-where-needed + Only infill under ceilings (default: no) Support material options: --support-material Generate support material for overhangs diff --git a/lib/Slic3r/Config.pm b/lib/Slic3r/Config.pm index f693ba00c..54a82b3c3 100644 --- a/lib/Slic3r/Config.pm +++ b/lib/Slic3r/Config.pm @@ -380,6 +380,13 @@ our $Options = { min => 0, default => 0, }, + 'infill_only_where_needed' => { + label => 'Only infill where needed', + tooltip => 'This option will limit infill to the areas actually needed for supporting ceilings (it will act as internal support material).', + cli => 'infill-only-where-needed!', + type => 'bool', + default => 0, + }, # flow options 'extrusion_width' => { diff --git a/lib/Slic3r/GUI/Tab.pm b/lib/Slic3r/GUI/Tab.pm index c9b292b72..d970da1bd 100644 --- a/lib/Slic3r/GUI/Tab.pm +++ b/lib/Slic3r/GUI/Tab.pm @@ -417,7 +417,8 @@ sub build { }, { title => 'Advanced', - options => [qw(infill_every_layers solid_infill_every_layers fill_angle solid_infill_below_area only_retract_when_crossing_perimeters)], + options => [qw(infill_every_layers infill_only_where_needed solid_infill_every_layers fill_angle + solid_infill_below_area only_retract_when_crossing_perimeters)], }, ]); diff --git a/lib/Slic3r/Layer/Region.pm b/lib/Slic3r/Layer/Region.pm index daab1a6d1..aedb45d02 100644 --- a/lib/Slic3r/Layer/Region.pm +++ b/lib/Slic3r/Layer/Region.pm @@ -2,7 +2,7 @@ package Slic3r::Layer::Region; use Moo; use Slic3r::ExtrusionPath ':roles'; -use Slic3r::Geometry qw(scale chained_path_items); +use Slic3r::Geometry qw(PI scale chained_path_items); use Slic3r::Geometry::Clipper qw(safety_offset union_ex diff_ex intersection_ex); use Slic3r::Surface ':types'; @@ -16,6 +16,7 @@ has 'layer' => ( has 'region' => (is => 'ro', required => 1); has 'perimeter_flow' => (is => 'rw'); has 'infill_flow' => (is => 'rw'); +has 'overhang_width' => (is => 'lazy'); # collection of spare segments generated by slicing the original geometry; # these need to be merged in continuos (closed) polylines @@ -64,6 +65,12 @@ sub _update_flows { : $self->region->flows->{infill}); } +sub _build_overhang_width { + my $self = shift; + my $threshold_rad = PI/2 - atan2($self->perimeter_flow->width / $self->height / 2, 1); + return scale($self->height * ((cos $threshold_rad) / (sin $threshold_rad))); +} + # build polylines from lines sub make_surfaces { my $self = shift; diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index 03fc77d88..d22bcb493 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -367,6 +367,7 @@ sub export_gcode { # they will be split in internal and internal-solid surfaces $status_cb->(60, "Generating horizontal shells"); $_->discover_horizontal_shells for @{$self->objects}; + $_->clip_fill_surfaces for @{$self->objects}; # combine fill surfaces to honor the "infill every N layers" option $status_cb->(70, "Combining infill"); diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index 87b7b4733..6a2ad1537 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -375,6 +375,53 @@ sub detect_surfaces_type { } } +sub clip_fill_surfaces { + my $self = shift; + return unless $Slic3r::Config->infill_only_where_needed; + + # We only want infill under ceilings; this is almost like an + # internal support material. + + my $additional_margin = scale 3; + + my @overhangs = (); + for my $layer_id (reverse 0..$#{$self->layers}) { + my $layer = $self->layers->[$layer_id]; + + # clip this layer's internal surfaces to @overhangs + foreach my $layerm (@{$layer->regions}) { + my @new_internal = map Slic3r::Surface->new( + expolygon => $_, + surface_type => S_TYPE_INTERNAL, + ), + @{intersection_ex( + [ map @$_, @overhangs ], + [ map @{$_->expolygon}, grep $_->surface_type == S_TYPE_INTERNAL, @{$layerm->fill_surfaces} ], + )}; + @{$layerm->fill_surfaces} = ( + @new_internal, + (grep $_->surface_type != S_TYPE_INTERNAL, @{$layerm->fill_surfaces}), + ); + } + + # get this layer's overhangs + if ($layer_id > 0) { + my $lower_layer = $self->layers->[$layer_id-1]; + # loop through layer regions so that we can use each region's + # specific overhang width + foreach my $layerm (@{$layer->regions}) { + my $overhang_width = $layerm->overhang_width; + # we want to support any solid surface, not just tops + # (internal solids might have been generated) + push @overhangs, map $_->offset_ex($additional_margin), @{intersection_ex( + [ map @{$_->expolygon}, grep $_->surface_type != S_TYPE_INTERNAL, @{$layerm->fill_surfaces} ], + [ map @$_, map $_->offset_ex(-$overhang_width), @{$lower_layer->slices} ], + )}; + } + } + } +} + sub discover_horizontal_shells { my $self = shift; @@ -580,13 +627,15 @@ sub generate_support_material { my $self = shift; return if $self->layer_count < 2; - my $threshold_rad = $Slic3r::Config->support_material_threshold - ? deg2rad($Slic3r::Config->support_material_threshold + 1) # +1 makes the threshold inclusive - : PI/2 - atan2($self->layers->[1]->regions->[0]->perimeter_flow->width/$Slic3r::Config->layer_height/2, 1); - Slic3r::debugf "Threshold angle = %d°\n", rad2deg($threshold_rad); - + my $overhang_width; + if ($Slic3r::Config->support_material_threshold) { + my $threshold_rad = deg2rad($Slic3r::Config->support_material_threshold + 1); # +1 makes the threshold inclusive + Slic3r::debugf "Threshold angle = %d°\n", rad2deg($threshold_rad); + $overhang_width = scale $Slic3r::Config->layer_height * ((cos $threshold_rad) / (sin $threshold_rad)); + } else { + $overhang_width = $self->layers->[1]->regions->[0]->overhang_width; + } my $flow = $self->print->support_material_flow; - my $overhang_width = $threshold_rad == 0 ? undef : scale $Slic3r::Config->layer_height * ((cos $threshold_rad) / (sin $threshold_rad)); my $distance_from_object = 1.5 * $flow->scaled_width; my $pattern_spacing = ($Slic3r::Config->support_material_spacing > $flow->spacing) ? $Slic3r::Config->support_material_spacing diff --git a/slic3r.pl b/slic3r.pl index 04aa1be9e..741da1de8 100755 --- a/slic3r.pl +++ b/slic3r.pl @@ -245,6 +245,8 @@ $j --solid-infill-below-area Force solid infill when a region has a smaller area than this threshold (mm^2, default: $config->{solid_infill_below_area}) + --infill-only-where-needed + Only infill under ceilings (default: no) Support material options: --support-material Generate support material for overhangs