diff --git a/lib/Slic3r.pm b/lib/Slic3r.pm index e0ca7326a..507b67c07 100644 --- a/lib/Slic3r.pm +++ b/lib/Slic3r.pm @@ -31,7 +31,6 @@ use Slic3r::Print; use Slic3r::Skein; use Slic3r::STL; use Slic3r::Surface; -use Slic3r::Surface::Bridge; # printer options our $nozzle_diameter = 0.5; diff --git a/lib/Slic3r/Fill.pm b/lib/Slic3r/Fill.pm index 0e2a50883..1c9373fd9 100644 --- a/lib/Slic3r/Fill.pm +++ b/lib/Slic3r/Fill.pm @@ -64,8 +64,7 @@ sub make_fill { # force 100% density and rectilinear fill for external surfaces if ($surface->surface_type ne 'internal') { - my $is_bridge = $surface->isa('Slic3r::Surface::Bridge') - && $surface->surface_type eq 'bottom'; + my $is_bridge = $layer->id > 0 && $surface->surface_type eq 'bottom'; $density = 1; $filler = $is_bridge ? 'rectilinear' : $Slic3r::solid_fill_pattern; $flow_width = $Slic3r::nozzle_diameter if $is_bridge; diff --git a/lib/Slic3r/Fill/Base.pm b/lib/Slic3r/Fill/Base.pm index 630dabd26..0ca81c3f7 100644 --- a/lib/Slic3r/Fill/Base.pm +++ b/lib/Slic3r/Fill/Base.pm @@ -24,7 +24,7 @@ sub infill_direction { } # use bridge angle - if ($surface->isa('Slic3r::Surface::Bridge') && defined $surface->bridge_angle) { + if ($surface->surface_type eq 'bottom' && $self->layer->id > 0 && defined $surface->bridge_angle) { Slic3r::debugf "Filling bridge with angle %d\n", $surface->bridge_angle; $rotate[0] = Slic3r::Geometry::deg2rad($surface->bridge_angle); } diff --git a/lib/Slic3r/Layer.pm b/lib/Slic3r/Layer.pm index 83ffceb08..5ae594ea1 100644 --- a/lib/Slic3r/Layer.pm +++ b/lib/Slic3r/Layer.pm @@ -32,7 +32,7 @@ has 'surfaces' => ( # collection of surfaces representing bridges has 'bridges' => ( is => 'rw', - #isa => 'ArrayRef[Slic3r::Surface::Bridge]', + #isa => 'ArrayRef[Slic3r::Surface]', default => sub { [] }, ); @@ -436,7 +436,7 @@ sub process_bridges { [ $bridge_offset ], ); - push @{$self->bridges}, map Slic3r::Surface::Bridge->cast_from_expolygon($_, + push @{$self->bridges}, map Slic3r::Surface->cast_from_expolygon($_, surface_type => $surface->surface_type, bridge_angle => $bridge_angle, ), @$intersection; @@ -446,32 +446,24 @@ sub process_bridges { # now we need to merge bridges to avoid overlapping { # build a list of unique bridge types - my $unique_type = sub { $_[0]->surface_type . "_" . ($_[0]->bridge_angle || '') }; - my @unique_types = (); - foreach my $bridge (@{$self->bridges}) { - my $type = $unique_type->($bridge); - push @unique_types, $type unless grep $_ eq $type, @unique_types; - } + my @surface_groups = Slic3r::Surface->group(@{$self->bridges}); # merge bridges of the same type, removing any of the bridges already merged; - # the order of @unique_types determines the priority between bridges having + # the order of @surface_groups determines the priority between bridges having # different surface_type or bridge_angle - my @bridges = (); - foreach my $type (@unique_types) { - my @surfaces = grep { $unique_type->($_) eq $type } @{$self->bridges}; - my $union = union_ex([ map $_->p, @surfaces ]); + @{$self->bridges} = (); + foreach my $surfaces (@surface_groups) { + my $union = union_ex([ map $_->p, @$surfaces ]); my $diff = diff_ex( [ map @$_, @$union ], - [ map $_->p, @bridges ], + [ map $_->p, @{$self->bridges} ], ); - push @bridges, map Slic3r::Surface::Bridge->cast_from_expolygon($_, - surface_type => $surfaces[0]->surface_type, - bridge_angle => $surfaces[0]->bridge_angle, + push @{$self->bridges}, map Slic3r::Surface->cast_from_expolygon($_, + surface_type => $surfaces->[0]->surface_type, + bridge_angle => $surfaces->[0]->bridge_angle, ), @$union; } - - @{$self->bridges} = @bridges; } } @@ -522,17 +514,18 @@ sub split_bridges_fills { [ $bridge->p ], ); - push @$surfaces, map Slic3r::Surface::Bridge->cast_from_expolygon($_, + push @$surfaces, map Slic3r::Surface->cast_from_expolygon($_, surface_type => $bridge->surface_type, bridge_angle => $bridge->bridge_angle, ), @$intersection; } # difference between fill_surfaces and bridges are the other surfaces - foreach my $surface (@surfaces) { - my $difference = diff_ex([ $surface->p ], [ map $_->p, @{$self->bridges} ]); + foreach my $type (qw(top bottom internal internal-solid)) { + my @my_surfaces = grep $_->surface_type eq $type, @surfaces; + my $difference = diff_ex([ map $_->p, @my_surfaces ], [ map $_->p, @{$self->bridges} ]); push @$surfaces, map Slic3r::Surface->cast_from_expolygon($_, - surface_type => $surface->surface_type), @$difference; + surface_type => $type), @$difference; } } } diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index 3fb5653dd..85a9fc7b3 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -4,7 +4,7 @@ use Moo; use Math::ConvexHull 1.0.4 qw(convex_hull); use Slic3r::Geometry qw(X Y PI); use Slic3r::Geometry::Clipper qw(explode_expolygons safety_offset diff_ex intersection_ex - offset JT_ROUND JT_MITER); + union_ex offset JT_ROUND JT_MITER); use XXX; has 'x_length' => ( @@ -220,27 +220,32 @@ sub discover_horizontal_shells { foreach my $surfaces (@{$self->layers->[$n]->fill_surfaces}) { my @neighbor = @$surfaces; - my $neighbor_p = [ map $_->p, @neighbor ]; # find intersection between @surfaces and current layer's surfaces # intersections have contours and holes - my $intersections = intersection_ex($surfaces_p, $neighbor_p); + my $new_internal_solid = intersection_ex( + $surfaces_p, + [ map $_->p, grep $_->surface_type =~ /internal/, @neighbor ], + ); + next if !@$new_internal_solid; - next if @$intersections == 0; + # internal-solid are the union of the existing internal-solid surfaces + # and new ones + my $internal_solid = union_ex([ + ( map $_->p, grep $_->surface_type eq 'internal-solid', @neighbor ), + ( map @$_, @$new_internal_solid ), + ]); # subtract intersections from layer surfaces to get resulting inner surfaces my $internal = diff_ex( - $neighbor_p, - [ - (map @$_, @$intersections), - (map $_->p, grep $_->surface_type !~ /internal/, @neighbor), - ], + [ map $_->p, grep $_->surface_type eq 'internal', @neighbor ], + [ map @$_, @$internal_solid ], ); Slic3r::debugf " %d internal-solid and %d internal surfaces found\n", - scalar(@$intersections), scalar(@$internal); + scalar(@$internal_solid), scalar(@$internal); # Note: due to floating point math we're going to get some very small - # polygons as $internal_polygons; they will be removed by removed_small_features() + # polygons as $internal; they will be removed by removed_small_features() # assign resulting inner surfaces to layer @$surfaces = (); @@ -251,15 +256,16 @@ sub discover_horizontal_shells { # assign new internal-solid surfaces to layer push @$surfaces, Slic3r::Surface->cast_from_expolygon ($_, surface_type => 'internal-solid') - for @$intersections; + for @$internal_solid; - for my $neigh_type (qw(top bottom)) { + # assign top and bottom surfaces to layer + foreach my $s (Slic3r::Surface->group(grep $_->surface_type =~ /top|bottom/, @neighbor)) { my $solid_surfaces = diff_ex( - [ map $_->p, grep $_->surface_type eq $neigh_type, @neighbor ], - [ map @$_, @$intersections, @$internal ], + [ map $_->p, @$s ], + [ map @$_, @$internal_solid, @$internal ], ); push @$surfaces, Slic3r::Surface->cast_from_expolygon - ($_, surface_type => $neigh_type) + ($_, surface_type => $s->[0]->surface_type, bridge_angle => $s->[0]->bridge_angle) for @$solid_surfaces; } } diff --git a/lib/Slic3r/Surface.pm b/lib/Slic3r/Surface.pm index 6786de9c5..dcb41569e 100644 --- a/lib/Slic3r/Surface.pm +++ b/lib/Slic3r/Surface.pm @@ -22,6 +22,8 @@ has 'surface_type' => ( # this integer represents the thickness of the surface expressed in layers has 'depth_layers' => (is => 'ro', default => sub {1}); +has 'bridge_angle' => (is => 'ro'); + sub cast_from_polygon { my $class = shift; my ($polygon, %args) = @_; @@ -47,6 +49,25 @@ sub cast_from_expolygon { ); } +# static method to group surfaces having same surface_type and bridge_angle +sub group { + my $class = shift; + my (@surfaces) = @_; + + my $unique_type = sub { $_[0]->surface_type . "_" . ($_[0]->bridge_angle || '') }; + my @unique_types = (); + foreach my $surface (@surfaces) { + my $type = $unique_type->($surface); + push @unique_types, $type unless grep $_ eq $type, @unique_types; + } + + my @groups = (); + foreach my $type (@unique_types) { + push @groups, [ grep { $unique_type->($_) eq $type } @surfaces ]; + } + return @groups; +} + sub add_hole { my $self = shift; my ($hole) = @_; diff --git a/lib/Slic3r/Surface/Bridge.pm b/lib/Slic3r/Surface/Bridge.pm deleted file mode 100644 index aba5a8652..000000000 --- a/lib/Slic3r/Surface/Bridge.pm +++ /dev/null @@ -1,8 +0,0 @@ -package Slic3r::Surface::Bridge; -use Moo; - -extends "Slic3r::Surface"; - -has 'bridge_angle' => (is => 'ro'); - -1;