From 6e6bc746367b4f50dfdac108ce067ac94ff31a30 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci <aar@cpan.org> Date: Sun, 30 Dec 2012 16:27:20 +0100 Subject: [PATCH] Added failing test case for troubleshooting unexpected filled holes. #858 --- MANIFEST | 1 + lib/Slic3r/Layer/Region.pm | 29 +++++++++++------------ lib/Slic3r/Test.pm | 17 +++++++++++++- t/loops.t | 47 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+), 15 deletions(-) create mode 100644 t/loops.t diff --git a/MANIFEST b/MANIFEST index 094ed02e9..83d89ef25 100644 --- a/MANIFEST +++ b/MANIFEST @@ -59,6 +59,7 @@ t/custom_gcode.t t/dynamic.t t/fill.t t/geometry.t +t/loops.t t/polyclip.t t/retraction.t t/serialize.t diff --git a/lib/Slic3r/Layer/Region.pm b/lib/Slic3r/Layer/Region.pm index beb579fc3..3a1d2b0fa 100644 --- a/lib/Slic3r/Layer/Region.pm +++ b/lib/Slic3r/Layer/Region.pm @@ -69,20 +69,8 @@ sub make_surfaces { my $self = shift; my ($loops) = @_; - return if !@$loops; - { - my $safety_offset = scale 0.1; - # merge everything - my $expolygons = [ map $_->offset_ex(-$safety_offset), @{union_ex(safety_offset($loops, $safety_offset))} ]; - - Slic3r::debugf " %d surface(s) having %d holes detected from %d polylines\n", - scalar(@$expolygons), scalar(map $_->holes, @$expolygons), scalar(@$loops); - - $self->slices([ - map Slic3r::Surface->new(expolygon => $_, surface_type => S_TYPE_INTERNAL), - @$expolygons - ]); - } + return if !@$loops; + $self->slices([ _merge_loops($loops) ]); # the contours must be offsetted by half extrusion width inwards { @@ -129,6 +117,19 @@ sub make_surfaces { } } +sub _merge_loops { + my ($loops) = @_; + + my $safety_offset = scale 0.1; + # merge everything + my $expolygons = [ map $_->offset_ex(-$safety_offset), @{union_ex(safety_offset($loops, $safety_offset))} ]; + + Slic3r::debugf " %d surface(s) having %d holes detected from %d polylines\n", + scalar(@$expolygons), scalar(map $_->holes, @$expolygons), scalar(@$loops); + + return map Slic3r::Surface->new(expolygon => $_, surface_type => S_TYPE_INTERNAL), @$expolygons; +} + sub make_perimeters { my $self = shift; diff --git a/lib/Slic3r/Test.pm b/lib/Slic3r/Test.pm index 3c92f2eab..1e4531cd4 100644 --- a/lib/Slic3r/Test.pm +++ b/lib/Slic3r/Test.pm @@ -7,7 +7,8 @@ our @ISA = qw(Exporter); our @EXPORT_OK = qw(_eq); use IO::Scalar; -use Slic3r::Geometry qw(epsilon); +use List::Util qw(first); +use Slic3r::Geometry qw(epsilon X Y Z); my %cuboids = ( '20mm_cube' => [20,20,20], @@ -58,6 +59,20 @@ sub _eq { return abs($a - $b) < epsilon; } +sub add_facet { + my ($facet, $vertices, $facets) = @_; + + push @$facets, []; + for my $i (0..2) { + my $v = first { $vertices->[$_][X] == $facet->[$i][X] && $vertices->[$_][Y] == $facet->[$i][Y] && $vertices->[$_][Z] == $facet->[$i][Z] } 0..$#$vertices; + if (!defined $v) { + push @$vertices, [ @{$facet->[$i]}[X,Y,Z] ]; + $v = $#$vertices; + } + $facets->[-1][$i] = $v; + } +} + package Slic3r::Test::GCodeReader; use Moo; diff --git a/t/loops.t b/t/loops.t new file mode 100644 index 000000000..c36505e4e --- /dev/null +++ b/t/loops.t @@ -0,0 +1,47 @@ +use Test::More; +use strict; +use warnings; + +plan tests => 4; + +BEGIN { + use FindBin; + use lib "$FindBin::Bin/../lib"; +} + +use Slic3r; +use Slic3r::Test; + +{ + my (@vertices, @facets) = (); + Slic3r::Test::add_facet($_, \@vertices, \@facets) for + # external surface below the slicing Z + [ [0,0,0], [20,0,10], [0,0,10] ], + [ [20,0,0], [20,20,10], [20,0,10] ], + [ [20,20,0], [0,20,10], [20,20,10] ], + [ [0,20,0], [0,0,10], [0,20,10] ], + + # external insetted surface above the slicing Z + [ [2,2,10], [18,2,10], [2,2,20] ], + [ [18,2,10], [18,18,10], [18,2,20] ], + [ [18,18,10], [2,18,10], [18,18,20] ], + [ [2,18,10], [2,2,10], [2,18,20] ], + + # insetted hole below the slicing Z + [ [15,5,0], [5,5,10], [15,5,10] ], + [ [15,15,0], [15,5,10], [15,15,10] ], + [ [5,15,0], [15,15,10], [5,15,10] ], + [ [5,5,0], [5,15,10], [5,5,10] ]; + + my $mesh = Slic3r::TriangleMesh->new(vertices => \@vertices, facets => \@facets); + my @lines = map $mesh->intersect_facet($_, 10), 0..$#facets; + my $loops = Slic3r::TriangleMesh::make_loops(\@lines); + is scalar(@$loops), 3, 'correct number of loops detected'; + is scalar(grep $_->is_counter_clockwise, @$loops), 2, 'correct number of ccw loops detected'; + + my @surfaces = Slic3r::Layer::Region::_merge_loops($loops); + is scalar(@surfaces), 1, 'one surface detected'; + is scalar(@{$surfaces[0]->expolygon})-1, 1, 'surface has one hole'; +} + +__END__