diff --git a/lib/Slic3r/ExPolygon.pm b/lib/Slic3r/ExPolygon.pm index ec3d92f566..8f244ecb71 100644 --- a/lib/Slic3r/ExPolygon.pm +++ b/lib/Slic3r/ExPolygon.pm @@ -30,13 +30,6 @@ sub offset_ex { return Slic3r::Geometry::Clipper::offset_ex(\@$self, @_); } -sub noncollapsing_offset_ex { - my $self = shift; - my ($distance, @params) = @_; - - return $self->offset_ex($distance + 1, @params); -} - sub bounding_box { my $self = shift; return $self->contour->bounding_box; diff --git a/t/adaptive_width.t b/t/adaptive_width.t new file mode 100644 index 0000000000..7a0baa7527 --- /dev/null +++ b/t/adaptive_width.t @@ -0,0 +1,92 @@ +use Test::More; +use strict; +use warnings; + +plan tests => 32; + +BEGIN { + use FindBin; + use lib "$FindBin::Bin/../lib"; + use local::lib "$FindBin::Bin/../local-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 $test = sub { + my ($expolygon, $fw, $expected, $descr) = @_; + + my $flow = Slic3r::Flow->new( + nozzle_diameter => 0.5, + height => 0.4, + width => $fw, + ); + my $slices = Slic3r::Surface::Collection->new; + $slices->append(Slic3r::Surface->new( + surface_type => S_TYPE_INTERNAL, + expolygon => $expolygon, + )); + my $config = Slic3r::Config::Full->new; + my $loops = Slic3r::ExtrusionPath::Collection->new; + my $gap_fill = Slic3r::ExtrusionPath::Collection->new; + my $fill_surfaces = Slic3r::Surface::Collection->new; + my $pg = Slic3r::Layer::PerimeterGenerator->new( + $slices, $flow->height, $flow, + $config, $config, $config, + $loops, $gap_fill, $fill_surfaces, + ); + $pg->process; + + $loops = $loops->flatten; + my @single = grep $_->isa('Slic3r::ExtrusionPath'), @$loops; + my @loops = grep $_->isa('Slic3r::ExtrusionLoop'), @$loops; + + if (0) { + require "Slic3r/SVG.pm"; + Slic3r::SVG::output( + "output.svg", + expolygons => [$expolygon], + polylines => [ map $_->isa('Slic3r::ExtrusionPath') ? $_->polyline : $_->polygon->split_at_first_point, @$loops ], + red_polylines => [ map $_->polyline, @$gap_fill ], + ); + } + + is scalar(@single), $expected->{single} // 0, "expected number of single lines ($descr)"; + is scalar(@loops), $expected->{loops} // 0, "expected number of loops ($descr)"; + is scalar(@$gap_fill), $expected->{gaps} // 0, "expected number of gap fills ($descr)"; + + if ($expected->{single}) { + ok abs($loops->[0]->width - $expected->{width}) < epsilon, "single line covers the full width ($descr)"; + } + if ($expected->{loops}) { + my $loop_width = $loops[0][0]->width; + my $gap_fill_width = @$gap_fill ? $gap_fill->[0]->width : 0; + ok $loop_width * $expected->{loops} * 2 + $gap_fill_width > $expected->{width} - epsilon, + "loop total width + gap fill covers the full width ($descr)"; + } + }; + + my $fw = 0.7; + my $test_rect = sub { + my ($width, $expected) = @_; + + my $e = Slic3r::ExPolygon->new([ scale_points [0,0], [100,0], [100,$width], [0,$width] ]); + $expected->{width} = $width; + $test->($e, $fw, $expected, $width); + }; + $test_rect->($fw * 1, { single => 1, gaps => 0 }); + $test_rect->($fw * 1.3, { single => 1, gaps => 0 }); + $test_rect->($fw * 1.5, { single => 1, gaps => 0 }); + $test_rect->($fw * 2, { loops => 1, gaps => 0 }); + $test_rect->($fw * 2.5, { loops => 1, gaps => 1 }); + $test_rect->($fw * 3, { loops => 1, gaps => 1 }); + $test_rect->($fw * 3.5, { loops => 2, gaps => 0 }); + $test_rect->($fw * 4, { loops => 2, gaps => 1 }); +} + +__END__ diff --git a/t/dynamic.t b/t/dynamic.t deleted file mode 100644 index 5d4d3ceb4e..0000000000 --- a/t/dynamic.t +++ /dev/null @@ -1,93 +0,0 @@ -use Test::More; -use strict; -use warnings; - -plan skip_all => 'variable-width paths are currently disabled'; -plan tests => 20; - -BEGIN { - use FindBin; - use lib "$FindBin::Bin/../lib"; - use local::lib "$FindBin::Bin/../local-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'; -} - -{ - local $Slic3r::Config = Slic3r::Config->new( - perimeters => 3, - ); - my $w = 0.7; - my $perimeter_flow = Slic3r::Flow->new( - nozzle_diameter => 0.5, - layer_height => 0.4, - width => $w, - ); - - my $print = Slic3r::Print->new; - my $region = Slic3r::Print::Region->new( - print => $print, - flows => { perimeter => $perimeter_flow }, - ); - push @{$print->regions}, $region; - my $object = Slic3r::Print::Object->new( - print => $print, - size => [1,1], - ); - my $make_layer = sub { - my ($width) = @_; - my $layer = Slic3r::Layer->new( - object => $object, - 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 => [], - ); - my $layerm = $layer->region(0); - $layer->make_perimeters; - return $layerm; - }; - - my %widths = ( - 1 * $w => { perimeters => 1, gaps => 0 }, - 1.3 * $w => { perimeters => 1, gaps => 1, gap_flow_spacing => $perimeter_flow->clone(width => 0.2 * $w)->spacing }, - 1.5 * $w => { perimeters => 1, gaps => 1, gap_flow_spacing => $perimeter_flow->clone(width => 0.5 * $w)->spacing }, - 2 * $w => { perimeters => 1, gaps => 1, gap_flow_spacing => $perimeter_flow->spacing }, - 2.5 * $w => { perimeters => 1, gaps => 1, gap_flow_spacing => $perimeter_flow->clone(width => 1.5 * $w)->spacing }, - 3 * $w => { perimeters => 2, gaps => 0 }, - 4 * $w => { perimeters => 2, gaps => 1, gap_flow_spacing => $perimeter_flow->spacing }, - ); - - foreach my $width (sort keys %widths) { - my $layerm = $make_layer->($width); - is scalar @{$layerm->perimeters}, $widths{$width}{perimeters}, 'right number of perimeters'; - is scalar @{$layerm->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 $_, @{$layerm->thin_fills}; - if (@gaps) { - ok +(!first { abs($_->flow_spacing - $widths{$width}{gap_flow_spacing}) > epsilon } @gaps), - 'flow spacing was dynamically adjusted'; - } - } -} - -__END__ diff --git a/xs/src/libslic3r/ExtrusionEntity.hpp b/xs/src/libslic3r/ExtrusionEntity.hpp index 73b64e2865..b5bff5ab35 100644 --- a/xs/src/libslic3r/ExtrusionEntity.hpp +++ b/xs/src/libslic3r/ExtrusionEntity.hpp @@ -142,7 +142,6 @@ class ExtrusionLoop : public ExtrusionEntity void split_at(const Point &point, bool prefer_non_overhang = false); void clip_end(double distance, ExtrusionPaths* paths) const; // Test, whether the point is extruded by a bridging flow. - // This used to be used to avoid placing seams on overhangs, but now the EdgeGrid is used instead. bool has_overhang_point(const Point &point) const; bool is_perimeter() const { return this->paths.front().role == erPerimeter diff --git a/xs/xsp/ExtrusionLoop.xsp b/xs/xsp/ExtrusionLoop.xsp index 11b728a912..290265b196 100644 --- a/xs/xsp/ExtrusionLoop.xsp +++ b/xs/xsp/ExtrusionLoop.xsp @@ -37,7 +37,7 @@ SV* ExtrusionLoop::arrayref() CODE: AV* av = newAV(); - av_fill(av, THIS->paths.size()-1); + if (!THIS->paths.empty()) av_extend(av, THIS->paths.size()-1); for (ExtrusionPaths::iterator it = THIS->paths.begin(); it != THIS->paths.end(); ++it) { av_store(av, it - THIS->paths.begin(), perl_to_SV_ref(*it)); }