This commit is contained in:
parent
c180a2de57
commit
74f2f45554
@ -81,6 +81,10 @@ sub contact_area {
|
|||||||
my %contact = (); # contact_z => [ polygons ]
|
my %contact = (); # contact_z => [ polygons ]
|
||||||
my %overhang = (); # contact_z => [ polygons ] - this stores the actual overhang supported by each contact layer
|
my %overhang = (); # contact_z => [ polygons ] - this stores the actual overhang supported by each contact layer
|
||||||
for my $layer_id (0 .. $#{$object->layers}) {
|
for my $layer_id (0 .. $#{$object->layers}) {
|
||||||
|
# note $layer_id might != $layer->id when raft_layers > 0
|
||||||
|
# so $layer_id == 0 means first object layer
|
||||||
|
# and $layer->id == 0 means first print layer (including raft)
|
||||||
|
|
||||||
if ($self->config->raft_layers == 0) {
|
if ($self->config->raft_layers == 0) {
|
||||||
next if $layer_id == 0;
|
next if $layer_id == 0;
|
||||||
} elsif (!$self->config->support_material) {
|
} elsif (!$self->config->support_material) {
|
||||||
@ -89,69 +93,76 @@ sub contact_area {
|
|||||||
last if $layer_id > 0;
|
last if $layer_id > 0;
|
||||||
}
|
}
|
||||||
my $layer = $object->layers->[$layer_id];
|
my $layer = $object->layers->[$layer_id];
|
||||||
my $lower_layer = $object->layers->[$layer_id-1];
|
|
||||||
|
|
||||||
# detect overhangs and contact areas needed to support them
|
# detect overhangs and contact areas needed to support them
|
||||||
my (@overhang, @contact) = ();
|
my (@overhang, @contact) = ();
|
||||||
foreach my $layerm (@{$layer->regions}) {
|
if ($layer_id == 0) {
|
||||||
my $fw = $layerm->perimeter_flow->scaled_width;
|
# this is the first object layer, so we're here just to get the object
|
||||||
my $diff;
|
# footprint for the raft
|
||||||
|
push @overhang, map $_->clone, map @$_, @{$layer->slices};
|
||||||
|
push @contact, @{offset(\@overhang, scale +MARGIN)};
|
||||||
|
} else {
|
||||||
|
my $lower_layer = $object->layers->[$layer_id-1];
|
||||||
|
foreach my $layerm (@{$layer->regions}) {
|
||||||
|
my $fw = $layerm->perimeter_flow->scaled_width;
|
||||||
|
my $diff;
|
||||||
|
|
||||||
# If a threshold angle was specified, use a different logic for detecting overhangs.
|
# If a threshold angle was specified, use a different logic for detecting overhangs.
|
||||||
if (defined $threshold_rad
|
if (defined $threshold_rad
|
||||||
|| $layer_id < $self->config->support_material_enforce_layers
|
|| $layer_id < $self->config->support_material_enforce_layers
|
||||||
|| $self->config->raft_layers > 0) {
|
|| $self->config->raft_layers > 0) {
|
||||||
my $d = defined $threshold_rad
|
my $d = defined $threshold_rad
|
||||||
? scale $lower_layer->height * ((cos $threshold_rad) / (sin $threshold_rad))
|
? scale $lower_layer->height * ((cos $threshold_rad) / (sin $threshold_rad))
|
||||||
: 0;
|
: 0;
|
||||||
|
|
||||||
$diff = diff(
|
|
||||||
offset([ map $_->p, @{$layerm->slices} ], -$d),
|
|
||||||
[ map @$_, @{$lower_layer->slices} ],
|
|
||||||
);
|
|
||||||
|
|
||||||
# only enforce spacing from the object ($fw/2) if the threshold angle
|
|
||||||
# is not too high: in that case, $d will be very small (as we need to catch
|
|
||||||
# very short overhangs), and such contact area would be eaten by the
|
|
||||||
# enforced spacing, resulting in high threshold angles to be almost ignored
|
|
||||||
$diff = diff(
|
|
||||||
offset($diff, $d - $fw/2),
|
|
||||||
[ map @$_, @{$lower_layer->slices} ],
|
|
||||||
) if $d > $fw/2;
|
|
||||||
} else {
|
|
||||||
$diff = diff(
|
|
||||||
offset([ map $_->p, @{$layerm->slices} ], -$fw/2),
|
|
||||||
[ map @$_, @{$lower_layer->slices} ],
|
|
||||||
);
|
|
||||||
|
|
||||||
# collapse very tiny spots
|
|
||||||
$diff = offset2($diff, -$fw/10, +$fw/10);
|
|
||||||
|
|
||||||
# $diff now contains the ring or stripe comprised between the boundary of
|
|
||||||
# lower slices and the centerline of the last perimeter in this overhanging layer.
|
|
||||||
# Void $diff means that there's no upper perimeter whose centerline is
|
|
||||||
# outside the lower slice boundary, thus no overhang
|
|
||||||
}
|
|
||||||
|
|
||||||
# TODO: this is the place to remove bridged areas
|
|
||||||
|
|
||||||
next if !@$diff;
|
|
||||||
push @overhang, @$diff; # NOTE: this is not the full overhang as it misses the outermost half of the perimeter width!
|
|
||||||
|
|
||||||
# Let's define the required contact area by using a max gap of half the upper
|
|
||||||
# extrusion width and extending the area according to the configured margin.
|
|
||||||
# We increment the area in steps because we don't want our support to overflow
|
|
||||||
# on the other side of the object (if it's very thin).
|
|
||||||
{
|
|
||||||
my @slices_margin = @{offset([ map @$_, @{$lower_layer->slices} ], $fw/2)};
|
|
||||||
for ($fw/2, map {scale MARGIN_STEP} 1..(MARGIN / MARGIN_STEP)) {
|
|
||||||
$diff = diff(
|
$diff = diff(
|
||||||
offset($diff, $_),
|
offset([ map $_->p, @{$layerm->slices} ], -$d),
|
||||||
\@slices_margin,
|
[ map @$_, @{$lower_layer->slices} ],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
# only enforce spacing from the object ($fw/2) if the threshold angle
|
||||||
|
# is not too high: in that case, $d will be very small (as we need to catch
|
||||||
|
# very short overhangs), and such contact area would be eaten by the
|
||||||
|
# enforced spacing, resulting in high threshold angles to be almost ignored
|
||||||
|
$diff = diff(
|
||||||
|
offset($diff, $d - $fw/2),
|
||||||
|
[ map @$_, @{$lower_layer->slices} ],
|
||||||
|
) if $d > $fw/2;
|
||||||
|
} else {
|
||||||
|
$diff = diff(
|
||||||
|
offset([ map $_->p, @{$layerm->slices} ], -$fw/2),
|
||||||
|
[ map @$_, @{$lower_layer->slices} ],
|
||||||
|
);
|
||||||
|
|
||||||
|
# collapse very tiny spots
|
||||||
|
$diff = offset2($diff, -$fw/10, +$fw/10);
|
||||||
|
|
||||||
|
# $diff now contains the ring or stripe comprised between the boundary of
|
||||||
|
# lower slices and the centerline of the last perimeter in this overhanging layer.
|
||||||
|
# Void $diff means that there's no upper perimeter whose centerline is
|
||||||
|
# outside the lower slice boundary, thus no overhang
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# TODO: this is the place to remove bridged areas
|
||||||
|
|
||||||
|
next if !@$diff;
|
||||||
|
push @overhang, @$diff; # NOTE: this is not the full overhang as it misses the outermost half of the perimeter width!
|
||||||
|
|
||||||
|
# Let's define the required contact area by using a max gap of half the upper
|
||||||
|
# extrusion width and extending the area according to the configured margin.
|
||||||
|
# We increment the area in steps because we don't want our support to overflow
|
||||||
|
# on the other side of the object (if it's very thin).
|
||||||
|
{
|
||||||
|
my @slices_margin = @{offset([ map @$_, @{$lower_layer->slices} ], $fw/2)};
|
||||||
|
for ($fw/2, map {scale MARGIN_STEP} 1..(MARGIN / MARGIN_STEP)) {
|
||||||
|
$diff = diff(
|
||||||
|
offset($diff, $_),
|
||||||
|
\@slices_margin,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
push @contact, @$diff;
|
||||||
}
|
}
|
||||||
push @contact, @$diff;
|
|
||||||
}
|
}
|
||||||
next if !@contact;
|
next if !@contact;
|
||||||
|
|
||||||
@ -176,7 +187,7 @@ sub contact_area {
|
|||||||
require "Slic3r/SVG.pm";
|
require "Slic3r/SVG.pm";
|
||||||
Slic3r::SVG::output("contact_" . $contact_z . ".svg",
|
Slic3r::SVG::output("contact_" . $contact_z . ".svg",
|
||||||
expolygons => union_ex(\@contact),
|
expolygons => union_ex(\@contact),
|
||||||
red_expolygons => \@overhang,
|
red_expolygons => union_ex(\@overhang),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,6 +107,7 @@ sub init_print {
|
|||||||
|
|
||||||
$model_name = [$model_name] if ref($model_name) ne 'ARRAY';
|
$model_name = [$model_name] if ref($model_name) ne 'ARRAY';
|
||||||
for my $model (map model($_, %params), @$model_name) {
|
for my $model (map model($_, %params), @$model_name) {
|
||||||
|
die "Unknown model in test" if !defined $model;
|
||||||
$model->arrange_objects($config);
|
$model->arrange_objects($config);
|
||||||
$print->add_model($model);
|
$print->add_model($model);
|
||||||
}
|
}
|
||||||
|
39
t/support.t
39
t/support.t
@ -1,4 +1,4 @@
|
|||||||
use Test::More tests => 13;
|
use Test::More tests => 14;
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
@ -9,7 +9,8 @@ BEGIN {
|
|||||||
|
|
||||||
use List::Util qw(first);
|
use List::Util qw(first);
|
||||||
use Slic3r;
|
use Slic3r;
|
||||||
use Slic3r::Geometry qw(epsilon);
|
use Slic3r::Geometry qw(epsilon scale);
|
||||||
|
use Slic3r::Geometry::Clipper qw(diff);
|
||||||
use Slic3r::Test;
|
use Slic3r::Test;
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -88,4 +89,38 @@ use Slic3r::Test;
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $config = Slic3r::Config->new_from_defaults;
|
||||||
|
$config->set('skirts', 0);
|
||||||
|
$config->set('raft_layers', 3);
|
||||||
|
$config->set('support_material_extrusion_width', 0.6);
|
||||||
|
$config->set('first_layer_extrusion_width', '100%');
|
||||||
|
my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
|
||||||
|
|
||||||
|
my $layer_id = 0;
|
||||||
|
my @raft = my @first_object_layer = ();
|
||||||
|
Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
|
||||||
|
my ($self, $cmd, $args, $info) = @_;
|
||||||
|
|
||||||
|
if ($info->{extruding} && $info->{dist_XY} > 0) {
|
||||||
|
if ($layer_id <= $config->raft_layers) {
|
||||||
|
# this is a raft layer or the first object layer
|
||||||
|
my $line = Slic3r::Line->new_scale([ $self->X, $self->Y ], [ $info->{new_X}, $info->{new_Y} ]);
|
||||||
|
my @path = $line->grow(scale($config->support_material_extrusion_width/2));
|
||||||
|
if ($layer_id < $config->raft_layers) {
|
||||||
|
# this is a raft layer
|
||||||
|
push @raft, @path;
|
||||||
|
} else {
|
||||||
|
push @first_object_layer, @path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} elsif ($cmd eq 'G1' && $info->{dist_Z} > 0) {
|
||||||
|
$layer_id++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ok !@{diff(\@first_object_layer, \@raft)},
|
||||||
|
'first object layer is completely supported by raft';
|
||||||
|
}
|
||||||
|
|
||||||
__END__
|
__END__
|
||||||
|
Loading…
Reference in New Issue
Block a user