Align infill across layers regardless of first-layer-specific extrusion width. Includes a good internal API refactoring and a fix to 3D honeycomb flow
This commit is contained in:
parent
93507bfd49
commit
64061267c8
8 changed files with 67 additions and 46 deletions
|
@ -195,28 +195,66 @@ sub make_fill {
|
|||
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->height : $surface->thickness;
|
||||
my $flow = $layerm->region->flow(
|
||||
$role,
|
||||
$h,
|
||||
$is_bridge,
|
||||
$is_bridge || $f->use_bridge_flow,
|
||||
$layerm->id == 0,
|
||||
-1,
|
||||
$layerm->object,
|
||||
);
|
||||
|
||||
my $f = $self->filler($filler);
|
||||
# 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->object->config->layer_height, # TODO: handle infill_every_layers?
|
||||
0, # no bridge
|
||||
0, # no first layer
|
||||
-1, # auto width
|
||||
$layerm->object,
|
||||
);
|
||||
$f->spacing($internal_flow->spacing);
|
||||
$using_internal_flow = 1;
|
||||
} else {
|
||||
$f->spacing($flow->spacing);
|
||||
}
|
||||
|
||||
$f->layer_id($layerm->id);
|
||||
$f->z($layerm->print_z);
|
||||
$f->angle(deg2rad($layerm->config->fill_angle));
|
||||
my ($params, @polylines) = $f->fill_surface(
|
||||
$f->loop_clipping(scale($flow->nozzle_diameter) * &Slic3r::LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER);
|
||||
my @polylines = $f->fill_surface(
|
||||
$surface,
|
||||
density => $density/100,
|
||||
flow => $flow,
|
||||
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,
|
||||
);
|
||||
}
|
||||
my $mm3_per_mm = $flow->mm3_per_mm;
|
||||
|
||||
# save into layer
|
||||
|
@ -224,18 +262,16 @@ sub make_fill {
|
|||
my $role = $is_bridge ? EXTR_ROLE_BRIDGE
|
||||
: $is_solid ? (($surface->surface_type == S_TYPE_TOP) ? EXTR_ROLE_TOPSOLIDFILL : EXTR_ROLE_SOLIDFILL)
|
||||
: EXTR_ROLE_FILL;
|
||||
|
||||
my $extrusion_height = $is_bridge ? $flow->width : $h;
|
||||
|
||||
push @fills, my $collection = Slic3r::ExtrusionPath::Collection->new;
|
||||
$collection->no_sort($params->{no_sort});
|
||||
$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 => $extrusion_height,
|
||||
height => $flow->height,
|
||||
), @polylines,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -7,22 +7,17 @@ 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) = @_;
|
||||
|
||||
# use bridge flow since most of this pattern hangs in air
|
||||
my $flow = Slic3r::Flow->new(
|
||||
width => $params{flow}->width,
|
||||
height => $params{flow}->height,
|
||||
nozzle_diameter => $params{flow}->nozzle_diameter,
|
||||
bridge => 1,
|
||||
);
|
||||
|
||||
my $expolygon = $surface->expolygon;
|
||||
my $bb = $expolygon->bounding_box;
|
||||
my $size = $bb->size;
|
||||
|
||||
my $distance = $flow->scaled_spacing / $params{density};
|
||||
my $distance = scale($self->spacing) / $params{density};
|
||||
|
||||
# align bounding box to a multiple of our honeycomb grid
|
||||
{
|
||||
|
@ -71,7 +66,7 @@ sub fill_surface {
|
|||
}
|
||||
|
||||
# TODO: return ExtrusionLoop objects to get better chained paths
|
||||
return { flow => $flow}, @polylines;
|
||||
return @polylines;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@ 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 adjust_solid_spacing {
|
||||
|
@ -17,6 +19,9 @@ sub adjust_solid_spacing {
|
|||
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;
|
||||
|
|
|
@ -15,22 +15,15 @@ sub fill_surface {
|
|||
my $expolygon = $surface->expolygon;
|
||||
my $bounding_box = $expolygon->bounding_box;
|
||||
|
||||
my $flow = $params{flow};
|
||||
my $min_spacing = $flow->scaled_spacing;
|
||||
my $min_spacing = scale($self->spacing);
|
||||
my $distance = $min_spacing / $params{density};
|
||||
|
||||
my $flow_spacing = $flow->spacing;
|
||||
if ($params{density} == 1 && !$params{dont_adjust}) {
|
||||
$distance = $self->adjust_solid_spacing(
|
||||
width => $bounding_box->size->[X],
|
||||
distance => $distance,
|
||||
);
|
||||
$flow = Slic3r::Flow->new_from_spacing(
|
||||
spacing => unscale($distance),
|
||||
nozzle_diameter => $flow->nozzle_diameter,
|
||||
layer_height => ($params{layer_height} or die "No layer_height supplied to fill_surface()"),
|
||||
bridge => $flow->bridge,
|
||||
);
|
||||
$self->spacing(unscale $distance);
|
||||
}
|
||||
|
||||
# compensate the overlap which is good for rectilinear but harmful for concentric
|
||||
|
@ -54,12 +47,11 @@ sub fill_surface {
|
|||
}
|
||||
|
||||
# clip the paths to prevent the extruder from getting exactly on the first point of the loop
|
||||
my $clip_length = scale($flow->nozzle_diameter) * &Slic3r::LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER;
|
||||
$_->clip_end($clip_length) for @paths;
|
||||
$_->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 { flow => $flow, no_sort => 1 }, @paths;
|
||||
return @paths;
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
|
@ -18,11 +18,11 @@ sub fill_surface {
|
|||
my $rotate_vector = $self->infill_direction($surface);
|
||||
|
||||
# cache hexagons math
|
||||
my $cache_id = sprintf "d%s_s%s", $params{density}, $params{flow}->spacing;
|
||||
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 = $params{flow}->scaled_spacing;
|
||||
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);
|
||||
|
@ -123,7 +123,7 @@ sub fill_surface {
|
|||
)};
|
||||
}
|
||||
|
||||
return { flow => $params{flow} }, @paths;
|
||||
return @paths;
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
|
@ -21,8 +21,7 @@ sub fill_surface {
|
|||
my $rotate_vector = $self->infill_direction($surface);
|
||||
$self->rotate_points($expolygon, $rotate_vector);
|
||||
|
||||
my $flow = $params{flow};
|
||||
my $distance_between_lines = $flow->scaled_spacing / $params{density} * $self->multiplier;
|
||||
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;
|
||||
|
@ -75,7 +74,7 @@ sub fill_surface {
|
|||
$_->translate(@{$translate->negative}) for @paths;
|
||||
$self->rotate_points_back(\@paths, $rotate_vector);
|
||||
|
||||
return { flow => $flow }, @paths;
|
||||
return @paths;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -18,8 +18,7 @@ sub fill_surface {
|
|||
my $rotate_vector = $self->infill_direction($surface);
|
||||
$self->rotate_points($expolygon, $rotate_vector);
|
||||
|
||||
my $flow = $params{flow} or die "No flow supplied to fill_surface()";
|
||||
my $min_spacing = $flow->scaled_spacing;
|
||||
my $min_spacing = scale($self->spacing);
|
||||
my $line_spacing = $min_spacing / $params{density};
|
||||
my $line_oscillation = $line_spacing - $min_spacing;
|
||||
my $is_line_pattern = $self->isa('Slic3r::Fill::Line');
|
||||
|
@ -31,12 +30,7 @@ sub fill_surface {
|
|||
width => $bounding_box->size->[X],
|
||||
distance => $line_spacing,
|
||||
);
|
||||
$flow = Slic3r::Flow->new_from_spacing(
|
||||
spacing => unscale($line_spacing),
|
||||
nozzle_diameter => $flow->nozzle_diameter,
|
||||
layer_height => ($params{layer_height} or die "No layer_height supplied to fill_surface()"),
|
||||
bridge => $flow->bridge,
|
||||
);
|
||||
$self->spacing(unscale $line_spacing);
|
||||
} else {
|
||||
# extend bounding box so that our pattern will be aligned with other layers
|
||||
$bounding_box->merge_point(Slic3r::Point->new(
|
||||
|
@ -105,7 +99,7 @@ sub fill_surface {
|
|||
# paths must be rotated back
|
||||
$self->rotate_points_back(\@polylines, $rotate_vector);
|
||||
|
||||
return { flow => $flow }, @polylines;
|
||||
return @polylines;
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
|
@ -13,7 +13,7 @@ Flow::new_from_config_width(FlowRole role, const ConfigOptionFloatOrPercent &wid
|
|||
float w;
|
||||
if (bridge_flow_ratio > 0) {
|
||||
// if bridge flow was requested, calculate bridge width
|
||||
w = Flow::_bridge_width(nozzle_diameter, bridge_flow_ratio);
|
||||
height = w = Flow::_bridge_width(nozzle_diameter, bridge_flow_ratio);
|
||||
} else if (!width.percent && width.value == 0) {
|
||||
// if user left option to 0, calculate a sane default width
|
||||
w = Flow::_auto_width(role, nozzle_diameter, height);
|
||||
|
|
Loading…
Reference in a new issue