New algorithm for overhang detection
This commit is contained in:
parent
015580629b
commit
7e875393f5
@ -60,6 +60,17 @@ sub pack {
|
|||||||
# no-op, this allows to use both packed and non-packed objects in Collections
|
# no-op, this allows to use both packed and non-packed objects in Collections
|
||||||
sub unpack { $_[0] }
|
sub unpack { $_[0] }
|
||||||
|
|
||||||
|
sub clone {
|
||||||
|
my $self = shift;
|
||||||
|
my %p = @_;
|
||||||
|
|
||||||
|
$p{polyline} ||= $self->polyline->clone;
|
||||||
|
return (ref $self)->new(
|
||||||
|
(map { $_ => $self->$_ } qw(polyline height flow_spacing role)),
|
||||||
|
%p,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
sub clip_with_polygon {
|
sub clip_with_polygon {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my ($polygon) = @_;
|
my ($polygon) = @_;
|
||||||
@ -71,16 +82,24 @@ sub clip_with_expolygon {
|
|||||||
my $self = shift;
|
my $self = shift;
|
||||||
my ($expolygon) = @_;
|
my ($expolygon) = @_;
|
||||||
|
|
||||||
my @paths = ();
|
return map $self->clone(polyline => $_),
|
||||||
foreach my $polyline ($self->polyline->clip_with_expolygon($expolygon)) {
|
$self->polyline->clip_with_expolygon($expolygon);
|
||||||
push @paths, (ref $self)->new(
|
}
|
||||||
polyline => $polyline,
|
|
||||||
height => $self->height,
|
sub intersect_expolygons {
|
||||||
flow_spacing => $self->flow_spacing,
|
my $self = shift;
|
||||||
role => $self->role,
|
my ($expolygons) = @_;
|
||||||
);
|
|
||||||
}
|
return map $self->clone(polyline => Slic3r::Polyline->new(@$_)),
|
||||||
return @paths;
|
@{Boost::Geometry::Utils::multi_polygon_multi_linestring_intersection($expolygons, [$self->polyline])};
|
||||||
|
}
|
||||||
|
|
||||||
|
sub subtract_expolygons {
|
||||||
|
my $self = shift;
|
||||||
|
my ($expolygons) = @_;
|
||||||
|
|
||||||
|
return map $self->clone(polyline => Slic3r::Polyline->new(@$_)),
|
||||||
|
@{Boost::Geometry::Utils::multi_linestring_multi_polygon_difference([$self->polyline], $expolygons)};
|
||||||
}
|
}
|
||||||
|
|
||||||
sub simplify {
|
sub simplify {
|
||||||
@ -141,22 +160,15 @@ sub split_at_acute_angles {
|
|||||||
# if the angle between $p[-2], $p[-1], $p3 is too acute
|
# if the angle between $p[-2], $p[-1], $p3 is too acute
|
||||||
# then consider $p3 only as a starting point of a new
|
# then consider $p3 only as a starting point of a new
|
||||||
# path and stop the current one as it is
|
# path and stop the current one as it is
|
||||||
push @paths, (ref $self)->new(
|
push @paths, $self->clone(polyline => Slic3r::Polyline->new(\@p));
|
||||||
polyline => Slic3r::Polyline->new(\@p),
|
|
||||||
role => $self->role,
|
|
||||||
height => $self->height,
|
|
||||||
);
|
|
||||||
@p = ($p3);
|
@p = ($p3);
|
||||||
push @p, grep $_, shift @points or last;
|
push @p, grep $_, shift @points or last;
|
||||||
} else {
|
} else {
|
||||||
push @p, $p3;
|
push @p, $p3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
push @paths, (ref $self)->new(
|
push @paths, $self->clone(polyline => Slic3r::Polyline->new(\@p))
|
||||||
polyline => Slic3r::Polyline->new(\@p),
|
if @p > 1;
|
||||||
role => $self->role,
|
|
||||||
height => $self->height,
|
|
||||||
) if @p > 1;
|
|
||||||
|
|
||||||
return @paths;
|
return @paths;
|
||||||
}
|
}
|
||||||
@ -251,12 +263,8 @@ sub detect_arcs {
|
|||||||
);
|
);
|
||||||
|
|
||||||
# points 0..$i form a linear path
|
# points 0..$i form a linear path
|
||||||
push @paths, (ref $self)->new(
|
push @paths, $self->clone(polyline => Slic3r::Polyline->new(@points[0..$i]))
|
||||||
polyline => Slic3r::Polyline->new(@points[0..$i]),
|
if $i > 0;
|
||||||
role => $self->role,
|
|
||||||
flow_spacing => $self->flow_spacing,
|
|
||||||
height => $self->height,
|
|
||||||
) if $i > 0;
|
|
||||||
|
|
||||||
# add our arc
|
# add our arc
|
||||||
push @paths, $arc;
|
push @paths, $arc;
|
||||||
@ -271,12 +279,8 @@ sub detect_arcs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# remaining points form a linear path
|
# remaining points form a linear path
|
||||||
push @paths, (ref $self)->new(
|
push @paths, $self->clone(polyline => Slic3r::Polyline->new(\@points))
|
||||||
polyline => Slic3r::Polyline->new(\@points),
|
if @points > 1;
|
||||||
role => $self->role,
|
|
||||||
flow_spacing => $self->flow_spacing,
|
|
||||||
height => $self->height,
|
|
||||||
) if @points > 1;
|
|
||||||
|
|
||||||
return @paths;
|
return @paths;
|
||||||
}
|
}
|
||||||
|
@ -5,11 +5,13 @@ use List::Util qw(min max first);
|
|||||||
use Slic3r::ExtrusionPath ':roles';
|
use Slic3r::ExtrusionPath ':roles';
|
||||||
use Slic3r::Geometry qw(scale unscale scaled_epsilon points_coincide PI X Y B);
|
use Slic3r::Geometry qw(scale unscale scaled_epsilon points_coincide PI X Y B);
|
||||||
use Slic3r::Geometry::Clipper qw(union_ex);
|
use Slic3r::Geometry::Clipper qw(union_ex);
|
||||||
|
use Slic3r::Surface ':types';
|
||||||
|
|
||||||
has 'config' => (is => 'ro', required => 1);
|
has 'config' => (is => 'ro', required => 1);
|
||||||
has 'multiple_extruders' => (is => 'ro', default => sub {0} );
|
has 'multiple_extruders' => (is => 'ro', default => sub {0} );
|
||||||
has 'layer_count' => (is => 'ro', required => 1 );
|
has 'layer_count' => (is => 'ro', required => 1 );
|
||||||
has 'layer' => (is => 'rw');
|
has 'layer' => (is => 'rw');
|
||||||
|
has '_layer_overhangs' => (is => 'rw');
|
||||||
has 'move_z_callback' => (is => 'rw');
|
has 'move_z_callback' => (is => 'rw');
|
||||||
has 'shift_x' => (is => 'rw', default => sub {0} );
|
has 'shift_x' => (is => 'rw', default => sub {0} );
|
||||||
has 'shift_y' => (is => 'rw', default => sub {0} );
|
has 'shift_y' => (is => 'rw', default => sub {0} );
|
||||||
@ -82,6 +84,11 @@ sub change_layer {
|
|||||||
my ($layer) = @_;
|
my ($layer) = @_;
|
||||||
|
|
||||||
$self->layer($layer);
|
$self->layer($layer);
|
||||||
|
$self->_layer_overhangs(
|
||||||
|
$layer->id > 0
|
||||||
|
? [ map $_->expolygon, grep $_->surface_type == S_TYPE_BOTTOM, map @{$_->slices}, @{$layer->regions} ]
|
||||||
|
: []
|
||||||
|
);
|
||||||
if ($self->config->avoid_crossing_perimeters) {
|
if ($self->config->avoid_crossing_perimeters) {
|
||||||
$self->layer_mp(Slic3r::GCode::MotionPlanner->new(
|
$self->layer_mp(Slic3r::GCode::MotionPlanner->new(
|
||||||
islands => union_ex([ map @$_, @{$layer->slices} ], undef, 1),
|
islands => union_ex([ map @$_, @{$layer->slices} ], undef, 1),
|
||||||
@ -152,8 +159,29 @@ sub extrude_loop {
|
|||||||
$extrusion_path->clip_end(scale $extrusion_path->flow_spacing * &Slic3r::LOOP_CLIPPING_LENGTH_OVER_SPACING);
|
$extrusion_path->clip_end(scale $extrusion_path->flow_spacing * &Slic3r::LOOP_CLIPPING_LENGTH_OVER_SPACING);
|
||||||
return '' if !@{$extrusion_path->polyline};
|
return '' if !@{$extrusion_path->polyline};
|
||||||
|
|
||||||
|
my @paths = ();
|
||||||
|
# detect overhanging/bridging perimeters
|
||||||
|
if ($extrusion_path->is_perimeter && @{$self->_layer_overhangs}) {
|
||||||
|
# get non-overhang paths by subtracting overhangs from the loop
|
||||||
|
push @paths,
|
||||||
|
$extrusion_path->subtract_expolygons($self->_layer_overhangs);
|
||||||
|
|
||||||
|
# get overhang paths by intersecting overhangs with the loop
|
||||||
|
push @paths,
|
||||||
|
map { $_->role(EXTR_ROLE_OVERHANG_PERIMETER); $_ }
|
||||||
|
$extrusion_path->intersect_expolygons($self->_layer_overhangs);
|
||||||
|
|
||||||
|
# reapply the nearest point search for starting point
|
||||||
|
# (TODO: choose the nearest point not on an overhang)
|
||||||
|
@paths = Slic3r::ExtrusionPath::Collection
|
||||||
|
->new(paths => [@paths])
|
||||||
|
->chained_path($last_pos);
|
||||||
|
} else {
|
||||||
|
push @paths, $extrusion_path;
|
||||||
|
}
|
||||||
|
|
||||||
# extrude along the path
|
# extrude along the path
|
||||||
my $gcode = $self->extrude_path($extrusion_path, $description);
|
my $gcode = join '', map $self->extrude_path($_, $description), @paths;
|
||||||
$self->wipe_path($extrusion_path->polyline);
|
$self->wipe_path($extrusion_path->polyline);
|
||||||
|
|
||||||
# make a little move inwards before leaving loop
|
# make a little move inwards before leaving loop
|
||||||
|
@ -267,15 +267,6 @@ sub make_perimeters {
|
|||||||
$role = EXTR_ROLE_CONTOUR_INTERNAL_PERIMETER;
|
$role = EXTR_ROLE_CONTOUR_INTERNAL_PERIMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($self->id > 0) {
|
|
||||||
# A perimeter is considered overhang if its centerline exceeds the lower layer slices
|
|
||||||
my $is_overhang = $is_contour
|
|
||||||
? @{diff([$polygon], \@lower_slices)}
|
|
||||||
: !@{intersection([$polygon], \@lower_slices)};
|
|
||||||
|
|
||||||
$role = EXTR_ROLE_OVERHANG_PERIMETER if $is_overhang;
|
|
||||||
}
|
|
||||||
|
|
||||||
push @loops, Slic3r::ExtrusionLoop->pack(
|
push @loops, Slic3r::ExtrusionLoop->pack(
|
||||||
polygon => $polygon,
|
polygon => $polygon,
|
||||||
role => $role,
|
role => $role,
|
||||||
|
Loading…
Reference in New Issue
Block a user