Several changes to support material, including a fix to prevent vertical overlapping and horizontal fusion of support and object

This commit is contained in:
Alessandro Ranellucci 2013-10-27 10:19:26 +01:00
parent c08d4cc798
commit 28e9682d0e
2 changed files with 67 additions and 41 deletions

View file

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

View file

@ -7,17 +7,16 @@ use Slic3r::Geometry qw(scale PI rad2deg deg2rad);
use Slic3r::Geometry::Clipper qw(offset diff union_ex intersection offset_ex offset2); use Slic3r::Geometry::Clipper qw(offset diff union_ex intersection offset_ex offset2);
use Slic3r::Surface ':types'; use Slic3r::Surface ':types';
has 'config' => (is => 'rw', default => sub { Slic3r::Config->new_from_defaults }); has 'config' => (is => 'rw', required => 1);
has 'flow' => (is => 'rw'); has 'flow' => (is => 'rw', required => 1);
use constant DEBUG_CONTACT_ONLY => 0;
sub generate { sub generate {
my ($self, $object) = @_; my ($self, $object) = @_;
$self->flow($object->print->support_material_flow);
$self->config($object->config);
# Determine the top surfaces of the support, defined as: # Determine the top surfaces of the support, defined as:
# contact = overhangs - margin # contact = overhangs - clearance + margin
# This method is responsible for identifying what contact surfaces # This method is responsible for identifying what contact surfaces
# should the support material expose to the object in order to guarantee # should the support material expose to the object in order to guarantee
# that it will be effective, regardless of how it's built below. # that it will be effective, regardless of how it's built below.
@ -64,8 +63,7 @@ sub contact_area {
my ($self, $object) = @_; my ($self, $object) = @_;
# how much we extend support around the actual contact area # how much we extend support around the actual contact area
#my $margin = $flow->scaled_width / 2; my $margin = $self->flow->scaled_width * 3;
my $margin = scale 3;
# increment used to reach $margin in steps to avoid trespassing thin objects # increment used to reach $margin in steps to avoid trespassing thin objects
my $margin_step = $margin/3; my $margin_step = $margin/3;
@ -123,6 +121,8 @@ sub contact_area {
# outside the lower slice boundary, thus no overhang # outside the lower slice boundary, thus no overhang
} }
# TODO: this is the place to remove bridged areas
next if !@$diff; next if !@$diff;
push @overhang, @{union_ex($diff)}; # NOTE: this is not the full overhang as it misses the outermost half of the perimeter width! push @overhang, @{union_ex($diff)}; # NOTE: this is not the full overhang as it misses the outermost half of the perimeter width!
@ -179,32 +179,30 @@ sub object_top {
# find object top surfaces # find object top surfaces
# we'll use them to clip our support and detect where does it stick # we'll use them to clip our support and detect where does it stick
my %top = (); # print_z => [ expolygons ] my %top = (); # print_z => [ expolygons ]
{ my $projection = [];
my $projection = []; foreach my $layer (reverse @{$object->layers}) {
foreach my $layer (reverse @{$object->layers}) { if (my @top = map @{$_->slices->filter_by_type(S_TYPE_TOP)}, @{$layer->regions}) {
if (my @top = map @{$_->slices->filter_by_type(S_TYPE_TOP)}, @{$layer->regions}) { # compute projection of the contact areas above this top layer
# compute projection of the contact areas above this top layer # first add all the 'new' contact areas to the current projection
# first add all the 'new' contact areas to the current projection # ('new' means all the areas that are lower than the last top layer
# ('new' means all the areas that are lower than the last top layer # we considered)
# we considered) my $min_top = min(keys %top) // max(keys %$contact);
my $min_top = min(keys %top) // max(keys %$contact); # use <= instead of just < because otherwise we'd ignore any contact regions
# use <= instead of just < because otherwise we'd ignore any contact regions # having the same Z of top layers
# having the same Z of top layers push @$projection, map @{$contact->{$_}}, grep { $_ > $layer->print_z && $_ <= $min_top } keys %$contact;
push @$projection, map @{$contact->{$_}}, grep { $_ > $layer->print_z && $_ <= $min_top } keys %$contact;
# now find whether any projection falls onto this top surface
# now find whether any projection falls onto this top surface my $touching = intersection($projection, [ map $_->p, @top ]);
my $touching = intersection($projection, [ map $_->p, @top ]); if (@$touching) {
if (@$touching) { # grow top surfaces so that interface and support generation are generated
# grow top surfaces so that interface and support generation are generated # with some spacing from object - it looks we don't need the actual
# with some spacing from object - it looks we don't need the actual # top shapes so this can be done here
# top shapes so this can be done here $top{ $layer->print_z } = offset($touching, $self->flow->scaled_spacing);
$top{ $layer->print_z } = offset($touching, $self->flow->scaled_spacing);
}
# remove the areas that touched from the projection that will continue on
# next, lower, top surfaces
$projection = diff($projection, $touching);
} }
# remove the areas that touched from the projection that will continue on
# next, lower, top surfaces
$projection = diff($projection, $touching);
} }
} }
@ -266,19 +264,23 @@ sub generate_interface_layers {
# count contact layer as interface layer # count contact layer as interface layer
for (my $i = $layer_id-1; $i >= 0 && $i > $layer_id-$interface_layers; $i--) { for (my $i = $layer_id-1; $i >= 0 && $i > $layer_id-$interface_layers; $i--) {
$z = $support_z->[$i]; $z = $support_z->[$i];
my @overlapping_layers = $self->overlapping_layers($i, $support_z);
my @overlapping_z = map $support_z->[$_], @overlapping_layers;
# Compute interface area on this layer as diff of upper contact area # Compute interface area on this layer as diff of upper contact area
# (or upper interface area) and layer slices. # (or upper interface area) and layer slices.
# This diff is responsible of the contact between support material and # This diff is responsible of the contact between support material and
# the top surfaces of the object. We should probably offset the top # the top surfaces of the object. We should probably offset the top
# surfaces before performing the diff, but this needs investigation. # surfaces vertically before performing the diff, but this needs
# investigation.
$this = $interface{$i} = diff( $this = $interface{$i} = diff(
[ [
@$this, # clipped projection of the current contact regions @$this, # clipped projection of the current contact regions
@{ $interface{$i} || [] }, # interface regions already applied to this layer @{ $interface{$i} || [] }, # interface regions already applied to this layer
], ],
[ [
@{ $top->{$z} || [] }, # top slices on this layer (map @$_, map $top->{$_}, grep exists $top->{$_}, @overlapping_z), # top slices on this layer
@{ $contact->{$z} || [] }, # contact regions on this layer (map @$_, map $contact->{$_}, grep exists $contact->{$_}, @overlapping_z), # contact regions on this layer
], ],
1, 1,
); );
@ -296,15 +298,18 @@ sub generate_base_layers {
{ {
for my $i (reverse 0 .. $#$support_z-1) { for my $i (reverse 0 .. $#$support_z-1) {
my $z = $support_z->[$i]; my $z = $support_z->[$i];
my @overlapping_layers = $self->overlapping_layers($i, $support_z);
my @overlapping_z = map $support_z->[$_], @overlapping_layers;
$base->{$i} = diff( $base->{$i} = diff(
[ [
@{ $base->{$i+1} || [] }, # support regions on upper layer @{ $base->{$i+1} || [] }, # support regions on upper layer
@{ $interface->{$i+1} || [] }, # interface regions on upper layer @{ $interface->{$i+1} || [] }, # interface regions on upper layer
], ],
[ [
@{ $top->{$z} || [] }, # top slices on this layer (map @$_, map $top->{$_}, grep exists $top->{$_}, @overlapping_z), # top slices on this layer
@{ $interface->{$i} || [] }, # interface regions on this layer (map @$_, map $interface->{$_}, grep exists $interface->{$_}, @overlapping_layers), # interface regions on this layer
@{ $contact->{$z} || [] }, # contact regions on this layer (map @$_, map $contact->{$_}, grep exists $contact->{$_}, @overlapping_z), # contact regions on this layer
], ],
1, 1,
); );
@ -356,6 +361,11 @@ sub generate_toolpaths {
my $interface = $interface->{$layer_id} || []; my $interface = $interface->{$layer_id} || [];
my $base = $base->{$layer_id} || []; my $base = $base->{$layer_id} || [];
if (DEBUG_CONTACT_ONLY) {
$interface = [];
$base = [];
}
if (0) { if (0) {
require "Slic3r/SVG.pm"; require "Slic3r/SVG.pm";
Slic3r::SVG::output("layer_" . $z . ".svg", Slic3r::SVG::output("layer_" . $z . ".svg",
@ -422,7 +432,7 @@ sub generate_toolpaths {
offset([ @$interface, @$contact_infill ], scale 3), offset([ @$interface, @$contact_infill ], scale 3),
[ @$interface, @$base, @$contact_infill ], [ @$interface, @$base, @$contact_infill ],
1, 1,
); ) if 0; # this causes bad overlapping with other layers as it doesn't take Z overlap into account
$base = diff( $base = diff(
$base, $base,
$interface, $interface,
@ -524,4 +534,18 @@ sub generate_toolpaths {
); );
} }
# this method returns the indices of the layers overlapping with the given one
sub overlapping_layers {
my ($self, $i, $support_z) = @_;
my $zmax = $support_z->[$i];
my $zmin = ($i == 0) ? 0 : $support_z->[$i-1];
return grep {
my $zmax2 = $support_z->[$_];
my $zmin2 = ($_ == 0) ? 0 : $support_z->[$_-1];
$zmax > $zmin2 && $zmin < $zmax2;
} 0..$#$support_z;
}
1; 1;