Large refactoring. Cleaner logic, smaller memory footprint.

This commit is contained in:
Alessandro Ranellucci 2011-11-23 12:29:27 +01:00
parent 13ef24b5eb
commit 8598b66b0a
6 changed files with 178 additions and 247 deletions

View file

@ -29,20 +29,6 @@ has 'surfaces' => (
default => sub { [] },
);
# collection of surfaces representing bridges
has 'bridges' => (
is => 'rw',
#isa => 'ArrayRef[Slic3r::Surface]',
default => sub { [] },
);
# collection of surfaces to make perimeters for
has 'perimeter_surfaces' => (
is => 'rw',
#isa => 'ArrayRef[Slic3r::Surface]',
default => sub { [] },
);
# ordered collection of extrusion paths to build all perimeters
has 'perimeters' => (
is => 'rw',
@ -58,10 +44,10 @@ has 'skirts' => (
);
# collection of surfaces generated by offsetting the innermost perimeter(s)
# they represent boundaries of areas to fill (grouped by original objects)
has 'fill_surfaces' => (
# they represent boundaries of areas to fill
has 'fill_boundaries' => (
is => 'rw',
#isa => 'ArrayRef[ArrayRef[Slic3r::Surface]]',
#isa => 'ArrayRef[Slic3r::Surface]',
default => sub { [] },
);
@ -352,6 +338,8 @@ sub remove_small_perimeters {
sub process_bridges {
my $self = shift;
my @bridges = ();
# a bottom surface on a layer > 0 is either a bridge or a overhang
# or a combination of both; any top surface is a candidate for
# reverse bridge processing
@ -426,8 +414,8 @@ sub process_bridges {
# now, extend our bridge by taking a portion of supporting surfaces
{
# offset the bridge by the specified amount of mm
my $bridge_overlap = 2 * $Slic3r::perimeters * $Slic3r::flow_width / $Slic3r::resolution;
# offset the bridge by the specified amount of mm (minimum 3)
my $bridge_overlap = 3 / $Slic3r::resolution;
my ($bridge_offset) = $expolygon->contour->offset($bridge_overlap, $Slic3r::resolution * 100, JT_MITER, 2);
# calculate the new bridge
@ -436,7 +424,7 @@ sub process_bridges {
[ $bridge_offset ],
);
push @{$self->bridges}, map Slic3r::Surface->cast_from_expolygon($_,
push @bridges, map Slic3r::Surface->cast_from_expolygon($_,
surface_type => $surface->surface_type,
bridge_angle => $bridge_angle,
), @$intersection;
@ -446,86 +434,52 @@ sub process_bridges {
# now we need to merge bridges to avoid overlapping
{
# build a list of unique bridge types
my @surface_groups = Slic3r::Surface->group(@{$self->bridges});
my @surface_groups = Slic3r::Surface->group(@bridges);
# merge bridges of the same type, removing any of the bridges already merged;
# the order of @surface_groups determines the priority between bridges having
# different surface_type or bridge_angle
@{$self->bridges} = ();
@bridges = ();
foreach my $surfaces (@surface_groups) {
my $union = union_ex([ map $_->p, @$surfaces ]);
my $diff = diff_ex(
[ map @$_, @$union ],
[ map $_->p, @{$self->bridges} ],
[ map $_->p, @bridges ],
);
push @{$self->bridges}, map Slic3r::Surface->cast_from_expolygon($_,
push @bridges, map Slic3r::Surface->cast_from_expolygon($_,
surface_type => $surfaces->[0]->surface_type,
bridge_angle => $surfaces->[0]->bridge_angle,
), @$union;
}
}
}
# generates a set of surfaces that will be used to make perimeters
# thus, we need to merge internal surfaces and bridges
sub detect_perimeter_surfaces {
my $self = shift;
# little optimization: skip the Clipper UNION if we have no bridges
if (!@{$self->bridges}) {
push @{$self->perimeter_surfaces}, @{$self->surfaces};
} else {
my $union = union_ex([
(map $_->p, grep $_->surface_type =~ /internal/, @{$self->surfaces}),
(map $_->p, @{$self->bridges}),
]);
# apply bridges to layer
{
my @surfaces = @{$self->surfaces};
@{$self->surfaces} = ();
# schedule perimeters for internal surfaces merged with bridges
push @{$self->perimeter_surfaces},
map Slic3r::Surface->cast_from_expolygon($_, surface_type => 'internal'),
@$union;
# schedule perimeters for the remaining surfaces
foreach my $type (qw(top bottom)) {
my $diff = diff_ex(
[ map $_->p, grep $_->surface_type eq $type, @{$self->surfaces} ],
[ map @$_, @$union ],
);
push @{$self->perimeter_surfaces},
map Slic3r::Surface->cast_from_expolygon($_, surface_type => $type),
@$diff;
}
}
}
# splits fill_surfaces in internal and bridge surfaces
sub split_bridges_fills {
my $self = shift;
foreach my $surfaces (@{$self->fill_surfaces}) {
my @surfaces = @$surfaces;
@$surfaces = ();
# intersect fill_surfaces with bridges to get actual bridges
foreach my $bridge (@{$self->bridges}) {
my $intersection = intersection_ex(
# intersect layer surfaces with bridges to get actual bridges
foreach my $bridge (@bridges) {
my $actual_bridge = intersection_ex(
[ map $_->p, @surfaces ],
[ $bridge->p ],
);
push @$surfaces, map Slic3r::Surface->cast_from_expolygon($_,
push @{$self->surfaces}, map Slic3r::Surface->cast_from_expolygon($_,
surface_type => $bridge->surface_type,
bridge_angle => $bridge->bridge_angle,
), @$intersection;
), @$actual_bridge;
}
# difference between fill_surfaces and bridges are the other surfaces
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 => $type), @$difference;
# difference between layer surfaces and bridges are the other surfaces
foreach my $group (Slic3r::Surface->group(@surfaces)) {
my $difference = diff_ex(
[ map $_->p, @$group ],
[ map $_->p, @bridges ],
);
push @{$self->surfaces}, map Slic3r::Surface->cast_from_expolygon($_,
surface_type => $group->[0]->surface_type), @$difference;
}
}
}