Permalink
Browse files

Bugfix: some holes being closed incorrectly. #858

  • Loading branch information...
1 parent 6e6bc74 commit 141a8d39898b3b933a422b4b6f70201f356aed54 @alexrj committed Dec 30, 2012
Showing with 29 additions and 6 deletions.
  1. +1 −1 lib/Slic3r/Geometry/Clipper.pm
  2. +21 −4 lib/Slic3r/Layer/Region.pm
  3. +7 −1 t/loops.t
@@ -14,7 +14,7 @@ our $clipper = Math::Clipper->new;
sub safety_offset {
my ($polygons, $factor) = @_;
- return Math::Clipper::offset($polygons, $factor || (scale 1e-05), 100000, JT_MITER, 2);
+ return Math::Clipper::offset($polygons, $factor // (scale 1e-05), 100000, JT_MITER, 2);
}
sub offset {
View
@@ -118,11 +118,28 @@ sub make_surfaces {
}
sub _merge_loops {
- my ($loops) = @_;
+ my ($loops, $safety_offset) = @_;
- my $safety_offset = scale 0.1;
- # merge everything
- my $expolygons = [ map $_->offset_ex(-$safety_offset), @{union_ex(safety_offset($loops, $safety_offset))} ];
+ # Input loops are not suitable for evenodd nor nonzero fill types, as we might get
+ # two consecutive concentric loops having the same winding order - and we have to
+ # respect such order. In that case, evenodd would create wrong inversions, and nonzero
+ # would ignore holes inside two concentric contours.
+ # So we're ordering loops and collapse consecutive concentric loops having the same
+ # winding order.
+ # TODO: find a faster algorithm for this.
+ my @loops = sort { $a->encloses_point($b->[0]) ? 0 : 1 } @$loops; # outer first
+ $safety_offset //= scale 0.1;
+ @loops = @{ safety_offset(\@loops, $safety_offset) };
+ my $expolygons = [];
+ while (my $loop = shift @loops) {
+ bless $loop, 'Slic3r::Polygon';
+ if ($loop->is_counter_clockwise) {
+ $expolygons = union_ex([ $loop, map @$_, @$expolygons ]);
+ } else {
+ $expolygons = diff_ex([ map @$_, @$expolygons ], [$loop]);
+ }
+ }
+ $expolygons = [ map $_->offset_ex(-$safety_offset), @$expolygons ];
Slic3r::debugf " %d surface(s) having %d holes detected from %d polylines\n",
scalar(@$expolygons), scalar(map $_->holes, @$expolygons), scalar(@$loops);
View
@@ -13,6 +13,12 @@ use Slic3r;
use Slic3r::Test;
{
+ # We only need to slice at one height, so we'll build a non-manifold mesh
+ # that still produces complete loops at that height. Triangular walls are
+ # enough for this purpose.
+ # Basically we want to check what happens when three concentric loops happen
+ # to be at the same height, the two external ones being ccw and the other being
+ # a hole, thus cw.
my (@vertices, @facets) = ();
Slic3r::Test::add_facet($_, \@vertices, \@facets) for
# external surface below the slicing Z
@@ -39,7 +45,7 @@ use Slic3r::Test;
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);
+ my @surfaces = Slic3r::Layer::Region::_merge_loops($loops, 0);
is scalar(@surfaces), 1, 'one surface detected';
is scalar(@{$surfaces[0]->expolygon})-1, 1, 'surface has one hole';
}

0 comments on commit 141a8d3

Please sign in to comment.