Merge branch 'dynamic-flow'
This commit is contained in:
commit
1c50c8a401
1
MANIFEST
1
MANIFEST
@ -54,6 +54,7 @@ t/arcs.t
|
|||||||
t/clean_polylines.t
|
t/clean_polylines.t
|
||||||
t/clipper.t
|
t/clipper.t
|
||||||
t/collinear.t
|
t/collinear.t
|
||||||
|
t/dynamic.t
|
||||||
t/fill.t
|
t/fill.t
|
||||||
t/geometry.t
|
t/geometry.t
|
||||||
t/polyclip.t
|
t/polyclip.t
|
||||||
|
@ -82,6 +82,13 @@ sub safety_offset {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub noncollapsing_offset_ex {
|
||||||
|
my $self = shift;
|
||||||
|
my ($distance, @params) = @_;
|
||||||
|
|
||||||
|
return $self->offset_ex($distance + 1, @params);
|
||||||
|
}
|
||||||
|
|
||||||
sub encloses_point {
|
sub encloses_point {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my ($point) = @_;
|
my ($point) = @_;
|
||||||
|
@ -178,18 +178,8 @@ sub make_fill {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# add thin fill regions
|
# add thin fill regions
|
||||||
{
|
push @fills, @{$layer->thin_fills};
|
||||||
my %args = (
|
push @fills_ordering_points, map $_->unpack->points->[0], @{$layer->thin_fills};
|
||||||
role => EXTR_ROLE_SOLIDFILL,
|
|
||||||
flow_spacing => $layer->perimeter_flow->spacing,
|
|
||||||
);
|
|
||||||
push @fills, map {
|
|
||||||
$_->isa('Slic3r::Polygon')
|
|
||||||
? (map $_->pack, Slic3r::ExtrusionLoop->new(polygon => $_, %args)->split_at_first_point)
|
|
||||||
: Slic3r::ExtrusionPath->pack(polyline => $_, %args),
|
|
||||||
} @{$layer->thin_fills};
|
|
||||||
}
|
|
||||||
push @fills_ordering_points, map $_->[0], @{$layer->thin_fills};
|
|
||||||
|
|
||||||
# organize infill paths using a shortest path search
|
# organize infill paths using a shortest path search
|
||||||
@fills = @{shortest_path([
|
@fills = @{shortest_path([
|
||||||
|
@ -58,7 +58,7 @@ sub fill_surface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# connect lines
|
# connect lines
|
||||||
{
|
unless ($params{dont_connect}) {
|
||||||
my $collection = Slic3r::ExtrusionPath::Collection->new(
|
my $collection = Slic3r::ExtrusionPath::Collection->new(
|
||||||
paths => [ map Slic3r::ExtrusionPath->new(polyline => Slic3r::Polyline->new(@$_), role => -1), @paths ],
|
paths => [ map Slic3r::ExtrusionPath->new(polyline => Slic3r::Polyline->new(@$_), role => -1), @paths ],
|
||||||
);
|
);
|
||||||
|
@ -57,6 +57,16 @@ sub _build_spacing {
|
|||||||
return $self->width - &Slic3r::OVERLAP_FACTOR * ($self->width - $min_flow_spacing);
|
return $self->width - &Slic3r::OVERLAP_FACTOR * ($self->width - $min_flow_spacing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub clone {
|
||||||
|
my $self = shift;
|
||||||
|
|
||||||
|
return (ref $self)->new(
|
||||||
|
nozzle_diameter => $self->nozzle_diameter,
|
||||||
|
layer_height => $self->layer_height,
|
||||||
|
@_,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
sub _build_scaled_width {
|
sub _build_scaled_width {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
return scale $self->width;
|
return scale $self->width;
|
||||||
|
@ -187,12 +187,14 @@ sub make_perimeters {
|
|||||||
# offsetting a polygon can result in one or many offset polygons
|
# offsetting a polygon can result in one or many offset polygons
|
||||||
my @new_offsets = ();
|
my @new_offsets = ();
|
||||||
foreach my $expolygon (@last_offsets) {
|
foreach my $expolygon (@last_offsets) {
|
||||||
my @offsets = map $_->offset_ex(+0.5*$distance), $expolygon->offset_ex(-1.5*$distance);
|
my @offsets = map $_->offset_ex(+0.5*$distance), $expolygon->noncollapsing_offset_ex(-1.5*$distance);
|
||||||
push @new_offsets, @offsets;
|
push @new_offsets, @offsets;
|
||||||
|
|
||||||
|
# where the above check collapses the expolygon, then there's no room for an inner loop
|
||||||
|
# and we can extract the gap for later processing
|
||||||
my $diff = diff_ex(
|
my $diff = diff_ex(
|
||||||
[ map @$_, $expolygon->offset_ex(-$distance) ],
|
[ map @$_, $expolygon->offset_ex(-0.5*$distance) ],
|
||||||
[ map @$_, @offsets ],
|
[ map @$_, map $_->offset_ex(+0.5*$distance), @offsets ], # should these be offsetted in a single pass?
|
||||||
);
|
);
|
||||||
push @gaps, grep $_->area >= $gap_area_threshold, @$diff;
|
push @gaps, grep $_->area >= $gap_area_threshold, @$diff;
|
||||||
}
|
}
|
||||||
@ -207,14 +209,69 @@ sub make_perimeters {
|
|||||||
my @fill_boundaries = map $_->offset_ex(-$distance), @last_offsets;
|
my @fill_boundaries = map $_->offset_ex(-$distance), @last_offsets;
|
||||||
$_->simplify(scale &Slic3r::RESOLUTION) for @fill_boundaries;
|
$_->simplify(scale &Slic3r::RESOLUTION) for @fill_boundaries;
|
||||||
push @{ $self->surfaces }, @fill_boundaries;
|
push @{ $self->surfaces }, @fill_boundaries;
|
||||||
|
}
|
||||||
|
|
||||||
|
# fill gaps
|
||||||
|
{
|
||||||
|
my $filler = Slic3r::Fill->new(print => $self->layer->object->print)->filler('rectilinear');
|
||||||
|
|
||||||
# detect the small gaps that we need to treat like thin polygons,
|
my $w = $self->perimeter_flow->width;
|
||||||
# thus generating the skeleton and using it to fill them
|
my @widths = (1.5 * $w, $w, 0.5 * $w); # worth trying 0.2 too?
|
||||||
push @{ $self->thin_fills },
|
foreach my $width (@widths) {
|
||||||
map $_->medial_axis($self->perimeter_flow->scaled_width),
|
my $flow = $self->perimeter_flow->clone(width => $width);
|
||||||
@gaps;
|
|
||||||
Slic3r::debugf " %d gaps filled\n", scalar @{ $self->thin_fills }
|
# extract the gaps having this width
|
||||||
if @{ $self->thin_fills };
|
my @this_width = map $_->offset_ex(+0.5*$flow->scaled_width),
|
||||||
|
map $_->noncollapsing_offset_ex(-0.5*$flow->scaled_width),
|
||||||
|
@gaps;
|
||||||
|
|
||||||
|
if (0) {
|
||||||
|
# fill gaps using dynamic extrusion width, by treating them like thin polygons,
|
||||||
|
# thus generating the skeleton and using it to fill them
|
||||||
|
my %path_args = (
|
||||||
|
role => EXTR_ROLE_SOLIDFILL,
|
||||||
|
flow_spacing => $flow->spacing,
|
||||||
|
);
|
||||||
|
push @{ $self->thin_fills }, map {
|
||||||
|
$_->isa('Slic3r::Polygon')
|
||||||
|
? (map $_->pack, Slic3r::ExtrusionLoop->new(polygon => $_, %path_args)->split_at_first_point) # we should keep these as loops
|
||||||
|
: Slic3r::ExtrusionPath->pack(polyline => $_, %path_args),
|
||||||
|
} map $_->medial_axis($flow->scaled_width), @this_width;
|
||||||
|
|
||||||
|
Slic3r::debugf " %d gaps filled with extrusion width = %s\n", scalar @this_width, $width
|
||||||
|
if @{ $self->thin_fills };
|
||||||
|
|
||||||
|
} else {
|
||||||
|
# fill gaps using zigzag infill
|
||||||
|
|
||||||
|
# since this is infill, we have to offset by half-extrusion width inwards
|
||||||
|
my @infill = map $_->offset_ex(-0.5*$flow->scaled_width), @this_width;
|
||||||
|
|
||||||
|
foreach my $expolygon (@infill) {
|
||||||
|
my @paths = $filler->fill_surface(
|
||||||
|
Slic3r::Surface->new(expolygon => $expolygon),
|
||||||
|
density => 1,
|
||||||
|
flow_spacing => $flow->spacing,
|
||||||
|
dont_connect => 1, # time-saver
|
||||||
|
);
|
||||||
|
my $params = shift @paths;
|
||||||
|
|
||||||
|
push @{ $self->thin_fills },
|
||||||
|
map Slic3r::ExtrusionPath->pack(
|
||||||
|
polyline => Slic3r::Polyline->new(@$_),
|
||||||
|
role => EXTR_ROLE_SOLIDFILL,
|
||||||
|
depth_layers => 1,
|
||||||
|
flow_spacing => $params->{flow_spacing},
|
||||||
|
), @paths;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# check what's left
|
||||||
|
@gaps = @{diff_ex(
|
||||||
|
[ map @$_, @gaps ],
|
||||||
|
[ map @$_, @this_width ],
|
||||||
|
)};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
79
t/dynamic.t
Normal file
79
t/dynamic.t
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
use Test::More;
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
plan tests => 20;
|
||||||
|
|
||||||
|
BEGIN {
|
||||||
|
use FindBin;
|
||||||
|
use lib "$FindBin::Bin/../lib";
|
||||||
|
}
|
||||||
|
|
||||||
|
use List::Util qw(first);
|
||||||
|
use Slic3r;
|
||||||
|
use Slic3r::Geometry qw(X Y scale epsilon);
|
||||||
|
use Slic3r::Surface ':types';
|
||||||
|
|
||||||
|
sub scale_points (@) { map [scale $_->[X], scale $_->[Y]], @_ }
|
||||||
|
|
||||||
|
{
|
||||||
|
my $square = Slic3r::ExPolygon->new([
|
||||||
|
scale_points [0,0], [10,0], [10,10], [0,10],
|
||||||
|
]);
|
||||||
|
|
||||||
|
my @offsets = $square->noncollapsing_offset_ex(- scale 5);
|
||||||
|
is scalar @offsets, 1, 'non-collapsing offset';
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $w = 0.7;
|
||||||
|
local $Slic3r::perimeter_flow = Slic3r::Flow->new(
|
||||||
|
nozzle_diameter => 0.5,
|
||||||
|
layer_height => 0.4,
|
||||||
|
width => $w,
|
||||||
|
);
|
||||||
|
local $Slic3r::Config = Slic3r::Config->new(
|
||||||
|
perimeters => 3,
|
||||||
|
);
|
||||||
|
|
||||||
|
my $make_layer = sub {
|
||||||
|
my ($width) = @_;
|
||||||
|
my $layer = Slic3r::Layer->new(
|
||||||
|
id => 1,
|
||||||
|
slices => [
|
||||||
|
Slic3r::Surface->new(
|
||||||
|
surface_type => S_TYPE_INTERNAL,
|
||||||
|
expolygon => Slic3r::ExPolygon->new([ scale_points [0,0], [50,0], [50,$width], [0,$width] ]),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
thin_walls => [],
|
||||||
|
);
|
||||||
|
$layer->make_perimeters;
|
||||||
|
return $layer;
|
||||||
|
};
|
||||||
|
|
||||||
|
my %widths = (
|
||||||
|
1 * $w => { perimeters => 1, gaps => 0 },
|
||||||
|
1.3 * $w => { perimeters => 1, gaps => 1, gap_flow_spacing => $Slic3r::perimeter_flow->clone(width => 0.2 * $w)->spacing },
|
||||||
|
1.5 * $w => { perimeters => 1, gaps => 1, gap_flow_spacing => $Slic3r::perimeter_flow->clone(width => 0.5 * $w)->spacing },
|
||||||
|
2 * $w => { perimeters => 1, gaps => 1, gap_flow_spacing => $Slic3r::perimeter_flow->spacing },
|
||||||
|
2.5 * $w => { perimeters => 1, gaps => 1, gap_flow_spacing => $Slic3r::perimeter_flow->clone(width => 1.5 * $w)->spacing },
|
||||||
|
3 * $w => { perimeters => 2, gaps => 0 },
|
||||||
|
4 * $w => { perimeters => 2, gaps => 1, gap_flow_spacing => $Slic3r::perimeter_flow->spacing },
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach my $width (sort keys %widths) {
|
||||||
|
my $layer = $make_layer->($width);
|
||||||
|
is scalar @{$layer->perimeters}, $widths{$width}{perimeters}, 'right number of perimeters';
|
||||||
|
is scalar @{$layer->thin_fills} ? 1 : 0, $widths{$width}{gaps},
|
||||||
|
($widths{$width}{gaps} ? 'gaps were filled' : 'no gaps detected'); # TODO: we should check the exact number of gaps, but we need a better medial axis algorithm
|
||||||
|
|
||||||
|
my @gaps = map $_->unpack, @{$layer->thin_fills};
|
||||||
|
if (@gaps) {
|
||||||
|
ok +(!first { abs($_->flow_spacing - $widths{$width}{gap_flow_spacing}) > epsilon } @gaps),
|
||||||
|
'flow spacing was dynamically adjusted';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__END__
|
Loading…
Reference in New Issue
Block a user