Rewrote Fill2.pm to C++, deleted Perl infills for good.

Removed dependency on Perl Math::PlanePath module.
Fixed compilation with Visual Studio and SLIC3R_DEBUG: Visual Studio older than 2015 does not support the prinf type specifier %zu. Use %Iu instead.
C++11 move semantics enabled.
This commit is contained in:
bubnikv 2016-11-02 10:47:00 +01:00
parent 3a31d37d35
commit 95ede7c4b8
49 changed files with 628 additions and 1803 deletions

View file

@ -1,308 +0,0 @@
package Slic3r::Fill;
use Moo;
use List::Util qw(max);
use Slic3r::ExtrusionPath ':roles';
use Slic3r::Fill::3DHoneycomb;
use Slic3r::Fill::Base;
use Slic3r::Fill::Concentric;
use Slic3r::Fill::Honeycomb;
use Slic3r::Fill::PlanePath;
use Slic3r::Fill::Rectilinear;
use Slic3r::Flow ':roles';
use Slic3r::Geometry qw(X Y PI scale chained_path deg2rad);
use Slic3r::Geometry::Clipper qw(union union_ex diff diff_ex intersection_ex offset offset2);
use Slic3r::Surface ':types';
has 'bounding_box' => (is => 'ro', required => 0);
has 'fillers' => (is => 'rw', default => sub { {} });
our %FillTypes = (
archimedeanchords => 'Slic3r::Fill::ArchimedeanChords',
rectilinear => 'Slic3r::Fill::Rectilinear',
grid => 'Slic3r::Fill::Grid',
flowsnake => 'Slic3r::Fill::Flowsnake',
octagramspiral => 'Slic3r::Fill::OctagramSpiral',
hilbertcurve => 'Slic3r::Fill::HilbertCurve',
line => 'Slic3r::Fill::Line',
concentric => 'Slic3r::Fill::Concentric',
honeycomb => 'Slic3r::Fill::Honeycomb',
'3dhoneycomb' => 'Slic3r::Fill::3DHoneycomb',
);
sub filler {
my $self = shift;
my ($filler) = @_;
if (!ref $self) {
return $FillTypes{$filler}->new;
}
$self->fillers->{$filler} ||= $FillTypes{$filler}->new(
bounding_box => $self->bounding_box,
);
return $self->fillers->{$filler};
}
sub make_fill {
my $self = shift;
my ($layerm) = @_;
Slic3r::debugf "Filling layer %d:\n", $layerm->layer->id;
my $fill_density = $layerm->region->config->fill_density;
my $infill_flow = $layerm->flow(FLOW_ROLE_INFILL);
my $solid_infill_flow = $layerm->flow(FLOW_ROLE_SOLID_INFILL);
my $top_solid_infill_flow = $layerm->flow(FLOW_ROLE_TOP_SOLID_INFILL);
my @surfaces = ();
# merge adjacent surfaces
# in case of bridge surfaces, the ones with defined angle will be attached to the ones
# without any angle (shouldn't this logic be moved to process_external_surfaces()?)
{
my @surfaces_with_bridge_angle = grep { $_->bridge_angle >= 0 } @{$layerm->fill_surfaces};
# group surfaces by distinct properties
my @groups = @{$layerm->fill_surfaces->group};
# merge compatible groups (we can generate continuous infill for them)
{
# cache flow widths and patterns used for all solid groups
# (we'll use them for comparing compatible groups)
my @is_solid = my @fw = my @pattern = ();
for (my $i = 0; $i <= $#groups; $i++) {
# we can only merge solid non-bridge surfaces, so discard
# non-solid surfaces
if ($groups[$i][0]->is_solid && (!$groups[$i][0]->is_bridge || $layerm->layer->id == 0)) {
$is_solid[$i] = 1;
$fw[$i] = ($groups[$i][0]->surface_type == S_TYPE_TOP)
? $top_solid_infill_flow->width
: $solid_infill_flow->width;
$pattern[$i] = $groups[$i][0]->is_external
? $layerm->region->config->external_fill_pattern
: 'rectilinear';
} else {
$is_solid[$i] = 0;
$fw[$i] = 0;
$pattern[$i] = 'none';
}
}
# loop through solid groups
for (my $i = 0; $i <= $#groups; $i++) {
next if !$is_solid[$i];
# find compatible groups and append them to this one
for (my $j = $i+1; $j <= $#groups; $j++) {
next if !$is_solid[$j];
if ($fw[$i] == $fw[$j] && $pattern[$i] eq $pattern[$j]) {
# groups are compatible, merge them
push @{$groups[$i]}, @{$groups[$j]};
splice @groups, $j, 1;
splice @is_solid, $j, 1;
splice @fw, $j, 1;
splice @pattern, $j, 1;
}
}
}
}
# give priority to bridges
@groups = sort { ($a->[0]->bridge_angle >= 0) ? -1 : 0 } @groups;
foreach my $group (@groups) {
my $union_p = union([ map $_->p, @$group ], 1);
# subtract surfaces having a defined bridge_angle from any other
if (@surfaces_with_bridge_angle && $group->[0]->bridge_angle < 0) {
$union_p = diff(
$union_p,
[ map $_->p, @surfaces_with_bridge_angle ],
1,
);
}
# subtract any other surface already processed
my $union = diff_ex(
$union_p,
[ map $_->p, @surfaces ],
1,
);
push @surfaces, map $group->[0]->clone(expolygon => $_), @$union;
}
}
# we need to detect any narrow surfaces that might collapse
# when adding spacing below
# such narrow surfaces are often generated in sloping walls
# by bridge_over_infill() and combine_infill() as a result of the
# subtraction of the combinable area from the layer infill area,
# which leaves small areas near the perimeters
# we are going to grow such regions by overlapping them with the void (if any)
# TODO: detect and investigate whether there could be narrow regions without
# any void neighbors
{
my $distance_between_surfaces = max(
$infill_flow->scaled_spacing,
$solid_infill_flow->scaled_spacing,
$top_solid_infill_flow->scaled_spacing,
);
my $collapsed = diff(
[ map @{$_->expolygon}, @surfaces ],
offset2([ map @{$_->expolygon}, @surfaces ], -$distance_between_surfaces/2, +$distance_between_surfaces/2),
1,
);
push @surfaces, map Slic3r::Surface->new(
expolygon => $_,
surface_type => S_TYPE_INTERNALSOLID,
), @{intersection_ex(
offset($collapsed, $distance_between_surfaces),
[
(map @{$_->expolygon}, grep $_->surface_type == S_TYPE_INTERNALVOID, @surfaces),
(@$collapsed),
],
1,
)};
}
if (0) {
require "Slic3r/SVG.pm";
Slic3r::SVG::output("fill_" . $layerm->print_z . ".svg",
expolygons => [ map $_->expolygon, grep !$_->is_solid, @surfaces ],
red_expolygons => [ map $_->expolygon, grep $_->is_solid, @surfaces ],
);
}
my @fills = ();
SURFACE: foreach my $surface (@surfaces) {
next if $surface->surface_type == S_TYPE_INTERNALVOID;
my $filler = $layerm->region->config->fill_pattern;
my $density = $fill_density;
my $role = ($surface->surface_type == S_TYPE_TOP) ? FLOW_ROLE_TOP_SOLID_INFILL
: $surface->is_solid ? FLOW_ROLE_SOLID_INFILL
: FLOW_ROLE_INFILL;
my $is_bridge = $layerm->layer->id > 0 && $surface->is_bridge;
my $is_solid = $surface->is_solid;
if ($surface->is_solid) {
$density = 100;
$filler = 'rectilinear';
if ($surface->is_external && !$is_bridge) {
$filler = $layerm->region->config->external_fill_pattern;
}
} else {
next SURFACE unless $density > 0;
}
# get filler object
my $f = $self->filler($filler);
# calculate the actual flow we'll be using for this infill
my $h = $surface->thickness == -1 ? $layerm->layer->height : $surface->thickness;
my $flow = $layerm->region->flow(
$role,
$h,
$is_bridge || $f->use_bridge_flow,
$layerm->layer->id == 0,
-1,
$layerm->layer->object,
);
# calculate flow spacing for infill pattern generation
my $using_internal_flow = 0;
if (!$is_solid && !$is_bridge) {
# it's internal infill, so we can calculate a generic flow spacing
# for all layers, for avoiding the ugly effect of
# misaligned infill on first layer because of different extrusion width and
# layer height
my $internal_flow = $layerm->region->flow(
FLOW_ROLE_INFILL,
$layerm->layer->object->config->layer_height, # TODO: handle infill_every_layers?
0, # no bridge
0, # no first layer
-1, # auto width
$layerm->layer->object,
);
$f->spacing($internal_flow->spacing);
$using_internal_flow = 1;
# } elsif ($surface->surface_type == S_TYPE_INTERNALBRIDGE) {
# # The internal bridging layer will be sparse.
# $f->spacing($flow->spacing * 2.);
} else {
$f->spacing($flow->spacing);
}
my $old_spacing = $f->spacing;
$f->layer_id($layerm->layer->id);
$f->z($layerm->layer->print_z);
$f->angle(deg2rad($layerm->region->config->fill_angle));
$f->loop_clipping(scale($flow->nozzle_diameter) * &Slic3r::LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER);
# apply half spacing using this flow's own spacing and generate infill
my @polylines = map $f->fill_surface(
$_,
density => $density/100,
layer_height => $h,
#FIXME Vojtech disabled the automatic extrusion width adjustment as this feature quite often
# generated extrusions with excessive widths.
# The goal of the automatic line width adjustment was to fill in a region without a gap, but because
# the filled regions are mostly not aligned with the fill direction, very likely
# the extrusion width adjustment causes more harm than good.
dont_adjust => 1,
), @{ $surface->offset(-scale($f->spacing)/2) };
next unless @polylines;
# calculate actual flow from spacing (which might have been adjusted by the infill
# pattern generator)
if ($using_internal_flow) {
# if we used the internal flow we're not doing a solid infill
# so we can safely ignore the slight variation that might have
# been applied to $f->flow_spacing
} else {
if (abs($old_spacing - $f->spacing) > 0.3 * $old_spacing) {
print "Infill: Extreme spacing adjustment, from: ", $old_spacing, " to: ", $f->spacing, "\n";
}
$flow = Slic3r::Flow->new_from_spacing(
spacing => $f->spacing,
nozzle_diameter => $flow->nozzle_diameter,
layer_height => $h,
bridge => $is_bridge || $f->use_bridge_flow,
);
}
my $mm3_per_mm = $flow->mm3_per_mm;
# save into layer
{
my $role = $is_bridge ? EXTR_ROLE_BRIDGE
: $is_solid ? (($surface->surface_type == S_TYPE_TOP) ? EXTR_ROLE_TOPSOLIDFILL : EXTR_ROLE_SOLIDFILL)
: EXTR_ROLE_FILL;
push @fills, my $collection = Slic3r::ExtrusionPath::Collection->new;
$collection->no_sort($f->no_sort);
$collection->append(
map Slic3r::ExtrusionPath->new(
polyline => $_,
role => $role,
mm3_per_mm => $mm3_per_mm,
width => $flow->width,
height => $flow->height,
), @polylines,
);
}
}
# add thin fill regions
foreach my $thin_fill (@{$layerm->thin_fills}) {
push @fills, Slic3r::ExtrusionPath::Collection->new($thin_fill);
}
return @fills;
}
1;

View file

@ -1,230 +0,0 @@
package Slic3r::Fill::3DHoneycomb;
use Moo;
extends 'Slic3r::Fill::Base';
use POSIX qw(ceil fmod);
use Slic3r::Geometry qw(scale scaled_epsilon);
use Slic3r::Geometry::Clipper qw(intersection_pl);
# require bridge flow since most of this pattern hangs in air
sub use_bridge_flow { 1 }
sub fill_surface {
my ($self, $surface, %params) = @_;
my $expolygon = $surface->expolygon;
my $bb = $expolygon->bounding_box;
my $size = $bb->size;
my $distance = scale($self->spacing) / $params{density};
# align bounding box to a multiple of our honeycomb grid module
# (a module is 2*$distance since one $distance half-module is
# growing while the other $distance half-module is shrinking)
{
my $min = $bb->min_point;
$min->translate(
-($bb->x_min % (2*$distance)),
-($bb->y_min % (2*$distance)),
);
$bb->merge_point($min);
}
# generate pattern
my @polylines = map Slic3r::Polyline->new(@$_),
makeGrid(
scale($self->z),
$distance,
ceil($size->x / $distance) + 1,
ceil($size->y / $distance) + 1, #//
(($self->layer_id / $surface->thickness_layers) % 2) + 1,
);
# move pattern in place
$_->translate($bb->x_min, $bb->y_min) for @polylines;
# clip pattern to boundaries
@polylines = @{intersection_pl(\@polylines, \@$expolygon)};
# connect lines
unless ($params{dont_connect} || !@polylines) { # prevent calling leftmost_point() on empty collections
my ($expolygon_off) = @{$expolygon->offset_ex(scaled_epsilon)};
my $collection = Slic3r::Polyline::Collection->new(@polylines);
@polylines = ();
foreach my $polyline (@{$collection->chained_path_from($collection->leftmost_point, 0)}) {
# try to append this polyline to previous one if any
if (@polylines) {
my $line = Slic3r::Line->new($polylines[-1]->last_point, $polyline->first_point);
if ($line->length <= 1.5*$distance && $expolygon_off->contains_line($line)) {
$polylines[-1]->append_polyline($polyline);
next;
}
}
# make a clone before $collection goes out of scope
push @polylines, $polyline->clone;
}
}
# TODO: return ExtrusionLoop objects to get better chained paths
return @polylines;
}
=head1 DESCRIPTION
Creates a contiguous sequence of points at a specified height that make
up a horizontal slice of the edges of a space filling truncated
octahedron tesselation. The octahedrons are oriented so that the
square faces are in the horizontal plane with edges parallel to the X
and Y axes.
Credits: David Eccles (gringer).
=head2 makeGrid(z, gridSize, gridWidth, gridHeight, curveType)
Generate a set of curves (array of array of 2d points) that describe a
horizontal slice of a truncated regular octahedron with a specified
grid square size.
=cut
sub makeGrid {
my ($z, $gridSize, $gridWidth, $gridHeight, $curveType) = @_;
my $scaleFactor = $gridSize;
my $normalisedZ = $z / $scaleFactor;
my @points = makeNormalisedGrid($normalisedZ, $gridWidth, $gridHeight, $curveType);
foreach my $lineRef (@points) {
foreach my $pointRef (@$lineRef) {
$pointRef->[0] *= $scaleFactor;
$pointRef->[1] *= $scaleFactor;
}
}
return @points;
}
=head1 FUNCTIONS
=cut
=head2 colinearPoints(offset, gridLength)
Generate an array of points that are in the same direction as the
basic printing line (i.e. Y points for columns, X points for rows)
Note: a negative offset only causes a change in the perpendicular
direction
=cut
sub colinearPoints {
my ($offset, $baseLocation, $gridLength) = @_;
my @points = ();
push @points, $baseLocation - abs($offset/2);
for (my $i = 0; $i < $gridLength; $i++) {
push @points, $baseLocation + $i + abs($offset/2);
push @points, $baseLocation + ($i+1) - abs($offset/2);
}
push @points, $baseLocation + $gridLength + abs($offset/2);
return @points;
}
=head2 colinearPoints(offset, baseLocation, gridLength)
Generate an array of points for the dimension that is perpendicular to
the basic printing line (i.e. X points for columns, Y points for rows)
=cut
sub perpendPoints {
my ($offset, $baseLocation, $gridLength) = @_;
my @points = ();
my $side = 2*(($baseLocation) % 2) - 1;
push @points, $baseLocation - $offset/2 * $side;
for (my $i = 0; $i < $gridLength; $i++) {
$side = 2*(($i+$baseLocation) % 2) - 1;
push @points, $baseLocation + $offset/2 * $side;
push @points, $baseLocation + $offset/2 * $side;
}
push @points, $baseLocation - $offset/2 * $side;
return @points;
}
=head2 trim(pointArrayRef, minX, minY, maxX, maxY)
Trims an array of points to specified rectangular limits. Point
components that are outside these limits are set to the limits.
=cut
sub trim {
my ($pointArrayRef, $minX, $minY, $maxX, $maxY) = @_;
foreach (@$pointArrayRef) {
$_->[0] = ($_->[0] < $minX) ? $minX : (($_->[0] > $maxX) ? $maxX : $_->[0]);
$_->[1] = ($_->[1] < $minY) ? $minY : (($_->[1] > $maxY) ? $maxY : $_->[1]);
}
}
=head2 makeNormalisedGrid(z, gridWidth, gridHeight, curveType)
Generate a set of curves (array of array of 2d points) that describe a
horizontal slice of a truncated regular octahedron with edge length 1.
curveType specifies which lines to print, 1 for vertical lines
(columns), 2 for horizontal lines (rows), and 3 for both.
=cut
sub makeNormalisedGrid {
my ($z, $gridWidth, $gridHeight, $curveType) = @_;
## offset required to create a regular octagram
my $octagramGap = 0.5;
# sawtooth wave function for range f($z) = [-$octagramGap .. $octagramGap]
my $a = sqrt(2); # period
my $wave = abs(fmod($z, $a) - $a/2)/$a*4 - 1;
my $offset = $wave * $octagramGap;
my @points = ();
if (($curveType & 1) != 0) {
for (my $x = 0; $x <= $gridWidth; $x++) {
my @xPoints = perpendPoints($offset, $x, $gridHeight);
my @yPoints = colinearPoints($offset, 0, $gridHeight);
# This is essentially @newPoints = zip(@xPoints, @yPoints)
my @newPoints = map [ $xPoints[$_], $yPoints[$_] ], 0..$#xPoints;
# trim points to grid edges
#trim(\@newPoints, 0, 0, $gridWidth, $gridHeight);
if ($x % 2 == 0){
push @points, [ @newPoints ];
} else {
push @points, [ reverse @newPoints ];
}
}
}
if (($curveType & 2) != 0) {
for (my $y = 0; $y <= $gridHeight; $y++) {
my @xPoints = colinearPoints($offset, 0, $gridWidth);
my @yPoints = perpendPoints($offset, $y, $gridWidth);
my @newPoints = map [ $xPoints[$_], $yPoints[$_] ], 0..$#xPoints;
# trim points to grid edges
#trim(\@newPoints, 0, 0, $gridWidth, $gridHeight);
if ($y % 2 == 0) {
push @points, [ @newPoints ];
} else {
push @points, [ reverse @newPoints ];
}
}
}
return @points;
}
1;

View file

@ -1,101 +0,0 @@
package Slic3r::Fill::Base;
use Moo;
has 'layer_id' => (is => 'rw');
has 'z' => (is => 'rw'); # in unscaled coordinates
has 'angle' => (is => 'rw'); # in radians, ccw, 0 = East
has 'spacing' => (is => 'rw'); # in unscaled coordinates
has 'loop_clipping' => (is => 'rw', default => sub { 0 }); # in scaled coordinates
has 'bounding_box' => (is => 'ro', required => 0); # Slic3r::Geometry::BoundingBox object
sub set_spacing {
my ($self, $spacing) = @_;
$self->spacing($spacing);
}
sub set_angle {
my ($self, $angle) = @_;
$self->angle($angle);
}
sub adjust_solid_spacing {
my $self = shift;
my %params = @_;
my $number_of_lines = int($params{width} / $params{distance}) + 1;
return $params{distance} if $number_of_lines <= 1;
my $extra_space = $params{width} % $params{distance};
return $params{distance} + $extra_space / ($number_of_lines - 1);
}
sub no_sort { 0 }
sub use_bridge_flow { 0 }
package Slic3r::Fill::WithDirection;
use Moo::Role;
use Slic3r::Geometry qw(PI rad2deg);
sub angles () { [0, PI/2] }
sub infill_direction {
my $self = shift;
my ($surface) = @_;
if (!defined $self->angle) {
warn "Using undefined infill angle";
$self->angle(0);
}
# set infill angle
my (@rotate);
$rotate[0] = $self->angle;
$rotate[1] = $self->bounding_box
? $self->bounding_box->center
: $surface->expolygon->bounding_box->center;
my $shift = $rotate[1]->clone;
if (defined $self->layer_id) {
# alternate fill direction
my $layer_num = $self->layer_id / $surface->thickness_layers;
my $angle = $self->angles->[$layer_num % @{$self->angles}];
$rotate[0] = $self->angle + $angle if $angle;
}
# use bridge angle
if ($surface->bridge_angle >= 0) {
Slic3r::debugf "Filling bridge with angle %d\n", rad2deg($surface->bridge_angle);
$rotate[0] = $surface->bridge_angle;
}
$rotate[0] += PI/2;
$shift->rotate(@rotate);
return [\@rotate, $shift];
}
# this method accepts any object that implements rotate() and translate()
sub rotate_points {
my $self = shift;
my ($expolygon, $rotate_vector) = @_;
# rotate points
my ($rotate, $shift) = @$rotate_vector;
$rotate = [ -$rotate->[0], $rotate->[1] ];
$expolygon->rotate(@$rotate);
$expolygon->translate(@$shift);
}
sub rotate_points_back {
my $self = shift;
my ($paths, $rotate_vector) = @_;
my ($rotate, $shift) = @$rotate_vector;
$shift = [ map -$_, @$shift ];
$_->translate(@$shift) for @$paths;
$_->rotate(@$rotate) for @$paths;
}
1;

View file

@ -1,57 +0,0 @@
package Slic3r::Fill::Concentric;
use Moo;
extends 'Slic3r::Fill::Base';
use Slic3r::Geometry qw(scale unscale X);
use Slic3r::Geometry::Clipper qw(offset offset2 union_pt_chained);
sub no_sort { 1 }
sub fill_surface {
my $self = shift;
my ($surface, %params) = @_;
# no rotation is supported for this infill pattern
my $expolygon = $surface->expolygon;
my $bounding_box = $expolygon->bounding_box;
my $min_spacing = scale($self->spacing);
my $distance = $min_spacing / $params{density};
if ($params{density} == 1 && !$params{dont_adjust}) {
$distance = $self->adjust_solid_spacing(
width => $bounding_box->size->[X],
distance => $distance,
);
$self->spacing(unscale $distance);
}
my @loops = my @last = map $_->clone, @$expolygon;
while (@last) {
push @loops, @last = @{offset2(\@last, -($distance + 0.5*$min_spacing), +0.5*$min_spacing)};
}
# generate paths from the outermost to the innermost, to avoid
# adhesion problems of the first central tiny loops
@loops = map Slic3r::Polygon->new(@$_),
reverse @{union_pt_chained(\@loops)};
# split paths using a nearest neighbor search
my @paths = ();
my $last_pos = Slic3r::Point->new(0,0);
foreach my $loop (@loops) {
push @paths, $loop->split_at_index($last_pos->nearest_point_index(\@$loop));
$last_pos = $paths[-1]->last_point;
}
# clip the paths to prevent the extruder from getting exactly on the first point of the loop
$_->clip_end($self->loop_clipping) for @paths;
@paths = grep $_->is_valid, @paths; # remove empty paths (too short, thus eaten by clipping)
# TODO: return ExtrusionLoop objects to get better chained paths
return @paths;
}
1;

View file

@ -1,129 +0,0 @@
package Slic3r::Fill::Honeycomb;
use Moo;
extends 'Slic3r::Fill::Base';
with qw(Slic3r::Fill::WithDirection);
has 'cache' => (is => 'rw', default => sub {{}});
use Slic3r::Geometry qw(PI X Y MIN MAX scale scaled_epsilon);
use Slic3r::Geometry::Clipper qw(intersection intersection_pl);
sub angles () { [0, PI/3, PI/3*2] }
sub fill_surface {
my $self = shift;
my ($surface, %params) = @_;
my $rotate_vector = $self->infill_direction($surface);
# cache hexagons math
my $cache_id = sprintf "d%s_s%s", $params{density}, $self->spacing;
my $m;
if (!($m = $self->cache->{$cache_id})) {
$m = $self->cache->{$cache_id} = {};
my $min_spacing = scale($self->spacing);
$m->{distance} = $min_spacing / $params{density};
$m->{hex_side} = $m->{distance} / (sqrt(3)/2);
$m->{hex_width} = $m->{distance} * 2; # $m->{hex_width} == $m->{hex_side} * sqrt(3);
my $hex_height = $m->{hex_side} * 2;
$m->{pattern_height} = $hex_height + $m->{hex_side};
$m->{y_short} = $m->{distance} * sqrt(3)/3;
$m->{x_offset} = $min_spacing / 2;
$m->{y_offset} = $m->{x_offset} * sqrt(3)/3;
$m->{hex_center} = Slic3r::Point->new($m->{hex_width}/2, $m->{hex_side});
}
my @polygons = ();
{
# adjust actual bounding box to the nearest multiple of our hex pattern
# and align it so that it matches across layers
my $bounding_box = $surface->expolygon->bounding_box;
{
# rotate bounding box according to infill direction
my $bb_polygon = $bounding_box->polygon;
$bb_polygon->rotate($rotate_vector->[0][0], $m->{hex_center});
$bounding_box = $bb_polygon->bounding_box;
# extend bounding box so that our pattern will be aligned with other layers
# $bounding_box->[X1] and [Y1] represent the displacement between new bounding box offset and old one
$bounding_box->merge_point(Slic3r::Point->new(
$bounding_box->x_min - ($bounding_box->x_min % $m->{hex_width}),
$bounding_box->y_min - ($bounding_box->y_min % $m->{pattern_height}),
));
}
my $x = $bounding_box->x_min;
while ($x <= $bounding_box->x_max) {
my $p = [];
my @x = ($x + $m->{x_offset}, $x + $m->{distance} - $m->{x_offset});
for (1..2) {
@$p = reverse @$p; # turn first half upside down
my @p = ();
for (my $y = $bounding_box->y_min; $y <= $bounding_box->y_max; $y += $m->{y_short} + $m->{hex_side} + $m->{y_short} + $m->{hex_side}) {
push @$p,
[ $x[1], $y + $m->{y_offset} ],
[ $x[0], $y + $m->{y_short} - $m->{y_offset} ],
[ $x[0], $y + $m->{y_short} + $m->{hex_side} + $m->{y_offset} ],
[ $x[1], $y + $m->{y_short} + $m->{hex_side} + $m->{y_short} - $m->{y_offset} ],
[ $x[1], $y + $m->{y_short} + $m->{hex_side} + $m->{y_short} + $m->{hex_side} + $m->{y_offset} ];
}
@x = map $_ + $m->{distance}, reverse @x; # draw symmetrical pattern
$x += $m->{distance};
}
push @polygons, Slic3r::Polygon->new(@$p);
}
$_->rotate(-$rotate_vector->[0][0], $m->{hex_center}) for @polygons;
}
my @paths;
if ($params{complete} || 1) {
# we were requested to complete each loop;
# in this case we don't try to make more continuous paths
@paths = map $_->split_at_first_point,
@{intersection([ $surface->p ], \@polygons)};
} else {
# consider polygons as polylines without re-appending the initial point:
# this cuts the last segment on purpose, so that the jump to the next
# path is more straight
@paths = @{intersection_pl(
[ map Slic3r::Polyline->new(@$_), @polygons ],
[ @{$surface->expolygon} ],
)};
# connect paths
if (@paths) { # prevent calling leftmost_point() on empty collections
my $collection = Slic3r::Polyline::Collection->new(@paths);
@paths = ();
foreach my $path (@{$collection->chained_path_from($collection->leftmost_point, 0)}) {
if (@paths) {
# distance between first point of this path and last point of last path
my $distance = $paths[-1]->last_point->distance_to($path->first_point);
if ($distance <= $m->{hex_width}) {
$paths[-1]->append_polyline($path);
next;
}
}
# make a clone before $collection goes out of scope
push @paths, $path->clone;
}
}
# clip paths again to prevent connection segments from crossing the expolygon boundaries
@paths = @{intersection_pl(
\@paths,
[ map @$_, @{$surface->expolygon->offset_ex(scaled_epsilon)} ],
)};
}
return @paths;
}
1;

View file

@ -1,118 +0,0 @@
package Slic3r::Fill::PlanePath;
use Moo;
extends 'Slic3r::Fill::Base';
with qw(Slic3r::Fill::WithDirection);
use Slic3r::Geometry qw(scale X1 Y1 X2 Y2);
use Slic3r::Geometry::Clipper qw(intersection_pl);
sub angles () { [0] }
sub multiplier () { 1 }
sub process_polyline {}
sub fill_surface {
my $self = shift;
my ($surface, %params) = @_;
# rotate polygons
my $expolygon = $surface->expolygon->clone;
my $rotate_vector = $self->infill_direction($surface);
$self->rotate_points($expolygon, $rotate_vector);
my $distance_between_lines = scale($self->spacing) / $params{density} * $self->multiplier;
# align infill across layers using the object's bounding box
my $bb_polygon = $self->bounding_box->polygon;
$self->rotate_points($bb_polygon, $rotate_vector);
my $bounding_box = $bb_polygon->bounding_box;
(ref $self) =~ /::([^:]+)$/;
my $path = "Math::PlanePath::$1"->new;
my $translate = Slic3r::Point->new(0,0); # vector
if ($path->x_negative || $path->y_negative) {
# if the curve extends on both positive and negative coordinate space,
# center our expolygon around origin
$translate = $bounding_box->center->negative;
} else {
# if the curve does not extend in negative coordinate space,
# move expolygon entirely in positive coordinate space
$translate = $bounding_box->min_point->negative;
}
$expolygon->translate(@$translate);
$bounding_box->translate(@$translate);
my ($n_lo, $n_hi) = $path->rect_to_n_range(
map { $_ / $distance_between_lines }
@{$bounding_box->min_point},
@{$bounding_box->max_point},
);
my $polyline = Slic3r::Polyline->new(
map [ map { $_ * $distance_between_lines } $path->n_to_xy($_) ], ($n_lo..$n_hi)
);
return {} if @$polyline <= 1;
$self->process_polyline($polyline, $bounding_box);
my @paths = @{intersection_pl([$polyline], \@$expolygon)};
if (0) {
require "Slic3r/SVG.pm";
Slic3r::SVG::output("fill.svg",
no_arrows => 1,
polygons => \@$expolygon,
green_polygons => [ $bounding_box->polygon ],
polylines => [ $polyline ],
red_polylines => \@paths,
);
}
# paths must be repositioned and rotated back
$_->translate(@{$translate->negative}) for @paths;
$self->rotate_points_back(\@paths, $rotate_vector);
return @paths;
}
package Slic3r::Fill::ArchimedeanChords;
use Moo;
extends 'Slic3r::Fill::PlanePath';
use Math::PlanePath::ArchimedeanChords;
package Slic3r::Fill::Flowsnake;
use Moo;
extends 'Slic3r::Fill::PlanePath';
use Math::PlanePath::Flowsnake;
use Slic3r::Geometry qw(X);
# Sorry, this fill is currently broken.
sub process_polyline {
my $self = shift;
my ($polyline, $bounding_box) = @_;
$_->[X] += $bounding_box->center->[X] for @$polyline;
}
package Slic3r::Fill::HilbertCurve;
use Moo;
extends 'Slic3r::Fill::PlanePath';
use Math::PlanePath::HilbertCurve;
package Slic3r::Fill::OctagramSpiral;
use Moo;
extends 'Slic3r::Fill::PlanePath';
use Math::PlanePath::OctagramSpiral;
sub multiplier () { sqrt(2) }
1;

View file

@ -1,172 +0,0 @@
package Slic3r::Fill::Rectilinear;
use Moo;
extends 'Slic3r::Fill::Base';
with qw(Slic3r::Fill::WithDirection);
has '_min_spacing' => (is => 'rw');
has '_line_spacing' => (is => 'rw');
has '_diagonal_distance' => (is => 'rw');
has '_line_oscillation' => (is => 'rw');
use Slic3r::Geometry qw(scale unscale scaled_epsilon);
use Slic3r::Geometry::Clipper qw(intersection_pl);
sub horizontal_lines { 0 }
sub fill_surface {
my $self = shift;
my ($surface, %params) = @_;
# rotate polygons so that we can work with vertical lines here
my $expolygon = $surface->expolygon->clone;
my $rotate_vector = $self->infill_direction($surface);
$self->rotate_points($expolygon, $rotate_vector);
$self->_min_spacing(scale $self->spacing);
$self->_line_spacing($self->_min_spacing / $params{density});
$self->_diagonal_distance($self->_line_spacing * 2);
$self->_line_oscillation($self->_line_spacing - $self->_min_spacing); # only for Line infill
my $bounding_box = $expolygon->bounding_box;
# define flow spacing according to requested density
if ($params{density} == 1 && !$params{dont_adjust}) {
my $old_spacing = $self->spacing;
$self->_line_spacing($self->adjust_solid_spacing(
width => $bounding_box->size->x,
distance => $self->_line_spacing,
));
$self->spacing(unscale $self->_line_spacing);
if (abs($old_spacing - $self->spacing) > 0.3 * $old_spacing) {
print "Infill2: Extreme spacing adjustment, from: ", $old_spacing, " to: ", $self->spacing, "\n";
}
} else {
# extend bounding box so that our pattern will be aligned with other layers
$bounding_box->merge_point(Slic3r::Point->new(
$bounding_box->x_min - ($bounding_box->x_min % $self->_line_spacing),
$bounding_box->y_min - ($bounding_box->y_min % $self->_line_spacing),
));
}
# generate the basic pattern
my $x_max = $bounding_box->x_max + scaled_epsilon;
my @lines = ();
for (my $x = $bounding_box->x_min; $x <= $x_max; $x += $self->_line_spacing) {
push @lines, $self->_line($#lines, $x, $bounding_box->y_min, $bounding_box->y_max);
}
if ($self->horizontal_lines) {
my $y_max = $bounding_box->y_max + scaled_epsilon;
for (my $y = $bounding_box->y_min; $y <= $y_max; $y += $self->_line_spacing) {
push @lines, Slic3r::Polyline->new(
[$bounding_box->x_min, $y],
[$bounding_box->x_max, $y],
);
}
}
# clip paths against a slightly larger expolygon, so that the first and last paths
# are kept even if the expolygon has vertical sides
# the minimum offset for preventing edge lines from being clipped is scaled_epsilon;
# however we use a larger offset to support expolygons with slightly skewed sides and
# not perfectly straight
my @polylines = @{intersection_pl(\@lines, $expolygon->offset(+scale 0.02))};
my $extra = $self->_min_spacing * &Slic3r::INFILL_OVERLAP_OVER_SPACING;
foreach my $polyline (@polylines) {
my ($first_point, $last_point) = @$polyline[0,-1];
if ($first_point->y > $last_point->y) { #>
($first_point, $last_point) = ($last_point, $first_point);
}
$first_point->set_y($first_point->y - $extra); #--
$last_point->set_y($last_point->y + $extra); #++
}
# connect lines
unless ($params{dont_connect} || !@polylines) { # prevent calling leftmost_point() on empty collections
# offset the expolygon by max(min_spacing/2, extra)
my ($expolygon_off) = @{$expolygon->offset_ex($self->_min_spacing/2)};
my $collection = Slic3r::Polyline::Collection->new(@polylines);
@polylines = ();
foreach my $polyline (@{$collection->chained_path_from($collection->leftmost_point, 0)}) {
if (@polylines) {
my $first_point = $polyline->first_point;
my $last_point = $polylines[-1]->last_point;
my @distance = map abs($first_point->$_ - $last_point->$_), qw(x y);
# TODO: we should also check that both points are on a fill_boundary to avoid
# connecting paths on the boundaries of internal regions
if ($self->_can_connect(@distance) && $expolygon_off->contains_line(Slic3r::Line->new($last_point, $first_point))) {
$polylines[-1]->append_polyline($polyline);
next;
}
}
# make a clone before $collection goes out of scope
push @polylines, $polyline->clone;
}
}
# paths must be rotated back
$self->rotate_points_back(\@polylines, $rotate_vector);
return @polylines;
}
sub _line {
my ($self, $i, $x, $y_min, $y_max) = @_;
return Slic3r::Polyline->new(
[$x, $y_min],
[$x, $y_max],
);
}
sub _can_connect {
my ($self, $dist_X, $dist_Y) = @_;
return $dist_X <= $self->_diagonal_distance
&& $dist_Y <= $self->_diagonal_distance;
}
package Slic3r::Fill::Line;
use Moo;
extends 'Slic3r::Fill::Rectilinear';
use Slic3r::Geometry qw(scaled_epsilon);
sub _line {
my ($self, $i, $x, $y_min, $y_max) = @_;
if ($i % 2) {
return Slic3r::Polyline->new(
[$x - $self->_line_oscillation, $y_min],
[$x + $self->_line_oscillation, $y_max],
);
} else {
return Slic3r::Polyline->new(
[$x, $y_min],
[$x, $y_max],
);
}
}
sub _can_connect {
my ($self, $dist_X, $dist_Y) = @_;
my $TOLERANCE = 10 * scaled_epsilon;
return ($dist_X >= ($self->_line_spacing - $self->_line_oscillation) - $TOLERANCE)
&& ($dist_X <= ($self->_line_spacing + $self->_line_oscillation) + $TOLERANCE)
&& $dist_Y <= $self->_diagonal_distance;
}
package Slic3r::Fill::Grid;
use Moo;
extends 'Slic3r::Fill::Rectilinear';
sub angles () { [0] }
sub horizontal_lines { 1 }
1;

View file

@ -1,294 +0,0 @@
# This is derived from Fill.pm
# and it uses the C++ fillers.
package Slic3r::Fill2;
use Moo;
use List::Util qw(max);
use Slic3r::ExtrusionPath ':roles';
use Slic3r::Flow ':roles';
use Slic3r::Geometry qw(X Y PI scale chained_path deg2rad);
use Slic3r::Geometry::Clipper qw(union union_ex diff diff_ex intersection_ex offset offset2);
use Slic3r::Surface ':types';
has 'bounding_box' => (is => 'ro', required => 0);
has 'fillers' => (is => 'rw', default => sub { {} });
sub filler {
my $self = shift;
my ($filler) = @_;
if (!ref $self) {
return Slic3r::Filler->new_from_type($filler);
}
#print "Filler: ", $filler, "\n";
$self->fillers->{$filler} ||= Slic3r::Filler->new_from_type($filler);
$self->fillers->{$filler}->set_bounding_box($self->bounding_box);
return $self->fillers->{$filler};
}
# Generate infills for Slic3r::Layer::Region.
# The Slic3r::Layer::Region at this point of time may contain
# surfaces of various types (internal/bridge/top/bottom/solid).
# The infills are generated on the groups of surfaces with a compatible type.
# Returns an array of Slic3r::ExtrusionPath::Collection objects containing the infills generaed now
# and the thin fills generated by generate_perimeters().
sub make_fill {
my $self = shift;
# of type - C++: LayerRegion, Perl: Slic3r::Layer::Region
my ($layerm) = @_;
Slic3r::debugf "Filling layer %d:\n", $layerm->layer->id;
my $fill_density = $layerm->region->config->fill_density;
my $infill_flow = $layerm->flow(FLOW_ROLE_INFILL);
my $solid_infill_flow = $layerm->flow(FLOW_ROLE_SOLID_INFILL);
my $top_solid_infill_flow = $layerm->flow(FLOW_ROLE_TOP_SOLID_INFILL);
# Surfaces are of the type Slic3r::Surface
my @surfaces = ();
# merge adjacent surfaces
# in case of bridge surfaces, the ones with defined angle will be attached to the ones
# without any angle (shouldn't this logic be moved to process_external_surfaces()?)
{
my @surfaces_with_bridge_angle = grep { $_->bridge_angle >= 0 } @{$layerm->fill_surfaces};
# group surfaces by distinct properties
# group is of type Slic3r::SurfaceCollection
my @groups = @{$layerm->fill_surfaces->group};
# merge compatible groups (we can generate continuous infill for them)
{
# cache flow widths and patterns used for all solid groups
# (we'll use them for comparing compatible groups)
my @is_solid = my @fw = my @pattern = ();
for (my $i = 0; $i <= $#groups; $i++) {
# we can only merge solid non-bridge surfaces, so discard
# non-solid surfaces
if ($groups[$i][0]->is_solid && (!$groups[$i][0]->is_bridge || $layerm->layer->id == 0)) {
$is_solid[$i] = 1;
$fw[$i] = ($groups[$i][0]->surface_type == S_TYPE_TOP)
? $top_solid_infill_flow->width
: $solid_infill_flow->width;
$pattern[$i] = $groups[$i][0]->is_external
? $layerm->region->config->external_fill_pattern
: 'rectilinear';
} else {
$is_solid[$i] = 0;
$fw[$i] = 0;
$pattern[$i] = 'none';
}
}
# loop through solid groups
for (my $i = 0; $i <= $#groups; $i++) {
next if !$is_solid[$i];
# find compatible groups and append them to this one
for (my $j = $i+1; $j <= $#groups; $j++) {
next if !$is_solid[$j];
if ($fw[$i] == $fw[$j] && $pattern[$i] eq $pattern[$j]) {
# groups are compatible, merge them
push @{$groups[$i]}, @{$groups[$j]};
splice @groups, $j, 1;
splice @is_solid, $j, 1;
splice @fw, $j, 1;
splice @pattern, $j, 1;
}
}
}
}
# give priority to bridges
@groups = sort { ($a->[0]->bridge_angle >= 0) ? -1 : 0 } @groups;
foreach my $group (@groups) {
# Make a union of polygons defining the infiill regions of a group, use a safety offset.
my $union_p = union([ map $_->p, @$group ], 1);
# Subtract surfaces having a defined bridge_angle from any other, use a safety offset.
if (@surfaces_with_bridge_angle && $group->[0]->bridge_angle < 0) {
$union_p = diff(
$union_p,
[ map $_->p, @surfaces_with_bridge_angle ],
1,
);
}
# subtract any other surface already processed
#FIXME Vojtech: Because the bridge surfaces came first, they are subtracted twice!
my $union = diff_ex(
$union_p,
[ map $_->p, @surfaces ],
1,
);
push @surfaces, map $group->[0]->clone(expolygon => $_), @$union;
}
}
# we need to detect any narrow surfaces that might collapse
# when adding spacing below
# such narrow surfaces are often generated in sloping walls
# by bridge_over_infill() and combine_infill() as a result of the
# subtraction of the combinable area from the layer infill area,
# which leaves small areas near the perimeters
# we are going to grow such regions by overlapping them with the void (if any)
# TODO: detect and investigate whether there could be narrow regions without
# any void neighbors
{
my $distance_between_surfaces = max(
$infill_flow->scaled_spacing,
$solid_infill_flow->scaled_spacing,
$top_solid_infill_flow->scaled_spacing,
);
my $collapsed = diff(
[ map @{$_->expolygon}, @surfaces ],
offset2([ map @{$_->expolygon}, @surfaces ], -$distance_between_surfaces/2, +$distance_between_surfaces/2),
1,
);
push @surfaces, map Slic3r::Surface->new(
expolygon => $_,
surface_type => S_TYPE_INTERNALSOLID,
), @{intersection_ex(
offset($collapsed, $distance_between_surfaces),
[
(map @{$_->expolygon}, grep $_->surface_type == S_TYPE_INTERNALVOID, @surfaces),
(@$collapsed),
],
1,
)};
}
if (0) {
require "Slic3r/SVG.pm";
Slic3r::SVG::output("fill_" . $layerm->print_z . ".svg",
expolygons => [ map $_->expolygon, grep !$_->is_solid, @surfaces ],
red_expolygons => [ map $_->expolygon, grep $_->is_solid, @surfaces ],
);
}
# Fills are of perl type Slic3r::ExtrusionPath::Collection, c++ type ExtrusionEntityCollection
my @fills = ();
SURFACE: foreach my $surface (@surfaces) {
next if $surface->surface_type == S_TYPE_INTERNALVOID;
my $filler = $layerm->region->config->fill_pattern;
my $density = $fill_density;
my $role = ($surface->surface_type == S_TYPE_TOP) ? FLOW_ROLE_TOP_SOLID_INFILL
: $surface->is_solid ? FLOW_ROLE_SOLID_INFILL
: FLOW_ROLE_INFILL;
my $is_bridge = $layerm->layer->id > 0 && $surface->is_bridge;
my $is_solid = $surface->is_solid;
if ($surface->is_solid) {
$density = 100;
$filler = 'rectilinear';
if ($surface->is_external && !$is_bridge) {
$filler = $layerm->region->config->external_fill_pattern;
}
} else {
next SURFACE unless $density > 0;
}
# get filler object
my $f = $self->filler($filler);
# calculate the actual flow we'll be using for this infill
my $h = $surface->thickness == -1 ? $layerm->layer->height : $surface->thickness;
my $flow = $layerm->region->flow(
$role,
$h,
$is_bridge || $f->use_bridge_flow,
$layerm->layer->id == 0,
-1,
$layerm->layer->object,
);
# calculate flow spacing for infill pattern generation
my $using_internal_flow = 0;
if (!$is_solid && !$is_bridge) {
# it's internal infill, so we can calculate a generic flow spacing
# for all layers, for avoiding the ugly effect of
# misaligned infill on first layer because of different extrusion width and
# layer height
my $internal_flow = $layerm->region->flow(
FLOW_ROLE_INFILL,
$layerm->layer->object->config->layer_height, # TODO: handle infill_every_layers?
0, # no bridge
0, # no first layer
-1, # auto width
$layerm->layer->object,
);
$f->set_spacing($internal_flow->spacing);
$using_internal_flow = 1;
} else {
$f->set_spacing($flow->spacing);
}
$f->set_layer_id($layerm->layer->id);
$f->set_z($layerm->layer->print_z);
$f->set_angle(deg2rad($layerm->region->config->fill_angle));
$f->set_loop_clipping(scale($flow->nozzle_diameter) * &Slic3r::LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER);
# apply half spacing using this flow's own spacing and generate infill
my @polylines = $f->fill_surface(
$surface,
density => $density/100,
layer_height => $h,
);
next unless @polylines;
# calculate actual flow from spacing (which might have been adjusted by the infill
# pattern generator)
if ($using_internal_flow) {
# if we used the internal flow we're not doing a solid infill
# so we can safely ignore the slight variation that might have
# been applied to $f->flow_spacing
} else {
$flow = Slic3r::Flow->new_from_spacing(
spacing => $f->spacing,
nozzle_diameter => $flow->nozzle_diameter,
layer_height => $h,
bridge => $is_bridge || $f->use_bridge_flow,
);
}
# save into layer
{
my $role = $is_bridge ? EXTR_ROLE_BRIDGE
: $is_solid ? (($surface->surface_type == S_TYPE_TOP) ? EXTR_ROLE_TOPSOLIDFILL : EXTR_ROLE_SOLIDFILL)
: EXTR_ROLE_FILL;
push @fills, my $collection = Slic3r::ExtrusionPath::Collection->new;
# Only concentric fills are not sorted.
$collection->no_sort($f->no_sort);
$collection->append(
map Slic3r::ExtrusionPath->new(
polyline => $_,
role => $role,
mm3_per_mm => $flow->mm3_per_mm,
width => $flow->width,
height => $flow->height,
), map @$_, @polylines,
);
}
}
# add thin fill regions
# thin_fills are of C++ Slic3r::ExtrusionEntityCollection, perl type Slic3r::ExtrusionPath::Collection
# Unpacks the collection, creates multiple collections per path.
# The path type could be ExtrusionPath, ExtrusionLoop or ExtrusionEntityCollection.
# Why the paths are unpacked?
foreach my $thin_fill (@{$layerm->thin_fills}) {
push @fills, Slic3r::ExtrusionPath::Collection->new($thin_fill);
}
return @fills;
}
1;

View file

@ -31,17 +31,6 @@ sub regions {
return [ map $self->get_region($_), 0..($self->region_count-1) ];
}
sub make_fill {
my ($self) = @_;
foreach my $layerm (@{$self->regions}) {
$layerm->fills->clear;
# Fearlessly enable the C++ fillers.
$layerm->fills->append($_) for $self->object->fill_maker2->make_fill($layerm);
# $layerm->fills->append($_) for $self->object->fill_maker->make_fill($layerm);
}
}
package Slic3r::Layer::Support;
our @ISA = qw(Slic3r::Layer);

View file

@ -544,8 +544,8 @@ sub process_layer {
}
# process infill
# $layerm->fills is a collection of ExtrusionPath::Collection objects, each one containing
# the ExtrusionPath objects of a certain infill "group" (also called "surface"
# $layerm->fills is a collection of Slic3r::ExtrusionPath::Collection objects (C++ class ExtrusionEntityCollection),
# each one containing the ExtrusionPath objects of a certain infill "group" (also called "surface"
# throughout the code). We can redefine the order of such Collections but we have to
# do each one completely at once.
foreach my $fill (@{$layerm->fills}) {

View file

@ -14,19 +14,6 @@ use Slic3r::Surface ':types';
# If enabled, phases of prepare_infill will be written into SVG files to an "out" directory.
our $SLIC3R_DEBUG_SLICE_PROCESSING = 0;
# TODO: lazy
sub fill_maker {
my $self = shift;
return Slic3r::Fill->new(bounding_box => $self->bounding_box);
}
# Vojtech's implementation: Create the C++ filler.
# TODO: lazy
sub fill_maker2 {
my $self = shift;
return Slic3r::Fill2->new(bounding_box => $self->bounding_box);
}
sub region_volumes {
my $self = shift;
return [ map $self->get_region_volumes($_), 0..($self->region_count - 1) ];
@ -617,12 +604,12 @@ sub infill {
thread_cb => sub {
my $q = shift;
while (defined (my $i = $q->dequeue)) {
$self->get_layer($i)->make_fill;
$self->get_layer($i)->make_fills;
}
},
no_threads_cb => sub {
foreach my $layer (@{$self->layers}) {
$layer->make_fill;
$layer->make_fills;
}
},
);
@ -678,14 +665,7 @@ sub _support_material {
);
} else {
# New supports, C++ implementation.
return Slic3r::Print::SupportMaterial2->new(
print_config => $self->print->config,
object_config => $self->config,
first_layer_flow => $first_layer_flow,
flow => $self->support_material_flow,
interface_flow => $self->support_material_flow(FLOW_ROLE_SUPPORT_MATERIAL_INTERFACE),
soluble_interface => ($self->config->support_material_contact_distance == 0),
);
return Slic3r::Print::SupportMaterial2->new($self);
}
}

View file

@ -761,10 +761,13 @@ sub generate_toolpaths {
# Allocate the fillers exclusively in the worker threads! Don't allocate them at the main thread,
# as Perl copies the C++ pointers by default, so then the C++ objects are shared between threads!
my %fillers = (
interface => $object->fill_maker2->filler('rectilinear'),
support => $object->fill_maker2->filler($pattern),
interface => Slic3r::Filler->new_from_type('rectilinear'),
support => Slic3r::Filler->new_from_type($pattern),
);
my $bounding_box = $object->bounding_box;
$fillers{interface}->set_bounding_box($object->bounding_box);
$fillers{support}->set_bounding_box($object->bounding_box);
# interface and contact infill
if (@$interface || @$contact_infill) {
$fillers{interface}->set_angle($interface_angle);