Skip to content

Commit

Permalink
Corrections to math. Threads are not always rectangles with semicircl…
Browse files Browse the repository at this point in the history
…es. Better calculation of overlap.
  • Loading branch information
alranel committed Dec 17, 2011
1 parent cd0fd80 commit 1e6ecd9
Show file tree
Hide file tree
Showing 13 changed files with 63 additions and 42 deletions.
4 changes: 3 additions & 1 deletion lib/Slic3r.pm
Expand Up @@ -67,8 +67,10 @@ our $infill_every_layers = 1;
# flow options
our $extrusion_width_ratio = 0;
our $bridge_flow_ratio = 1;
our $overlap_factor = 0.15;
our $overlap_factor = 0.5;
our $flow_width;
our $min_flow_spacing;
our $flow_spacing;

# print options
our $perimeters = 3;
Expand Down
27 changes: 23 additions & 4 deletions lib/Slic3r/Config.pm
Expand Up @@ -373,15 +373,34 @@ sub validate {
} else {
# here we calculate a sane default by matching the flow speed (at the nozzle)
# and the feed rate
$Slic3r::flow_width = (($Slic3r::nozzle_diameter**2) * PI + ($Slic3r::layer_height**2) * (4 - PI)) / (4 * $Slic3r::layer_height);
my $volume = ($Slic3r::nozzle_diameter**2) * PI/4;
my $shape_threshold = $Slic3r::nozzle_diameter * $Slic3r::layer_height
+ ($Slic3r::layer_height**2) * PI/4;
if ($volume >= $shape_threshold) {
# rectangle with semicircles at the ends
$Slic3r::flow_width = (($Slic3r::nozzle_diameter**2) * PI + ($Slic3r::layer_height**2) * (4 - PI)) / (4 * $Slic3r::layer_height);
} else {
# rectangle with squished semicircles at the ends
$Slic3r::flow_width = $Slic3r::nozzle_diameter * ($Slic3r::nozzle_diameter/$Slic3r::layer_height - 4/PI + 1);
}

my $max_flow_width = $Slic3r::nozzle_diameter * 1.2;
my $min_flow_width = $Slic3r::nozzle_diameter * 1.05;
my $max_flow_width = $Slic3r::nozzle_diameter * 1.4;
$Slic3r::flow_width = $max_flow_width if $Slic3r::flow_width > $max_flow_width;
$Slic3r::flow_width = $Slic3r::nozzle_diameter * 1.05
if $Slic3r::flow_width < $Slic3r::nozzle_diameter;
$Slic3r::flow_width = $min_flow_width if $Slic3r::flow_width < $min_flow_width;
}

if ($Slic3r::flow_width >= ($Slic3r::nozzle_diameter + $Slic3r::layer_height)) {
# rectangle with shrunk at the ends
$Slic3r::min_flow_spacing = $Slic3r::flow_width - $Slic3r::layer_height * (1 - PI/4);
} else {
# rectangle with shrunk semicircles at the ends
$Slic3r::min_flow_spacing = $Slic3r::flow_width * (1 - PI/4) + $Slic3r::nozzle_diameter * PI/4;
}
$Slic3r::flow_spacing = $Slic3r::flow_width - $Slic3r::overlap_factor * ($Slic3r::flow_width - $Slic3r::min_flow_spacing);

Slic3r::debugf "Flow width = $Slic3r::flow_width\n";
Slic3r::debugf "Flow spacing = $Slic3r::flow_spacing\n";

# --perimeters
die "Invalid value for --perimeters\n"
Expand Down
23 changes: 15 additions & 8 deletions lib/Slic3r/Extruder.pm
Expand Up @@ -76,7 +76,7 @@ sub extrude_loop {
my $extrusion_path = $loop->split_at($start_at);

# clip the path to avoid the extruder to get exactly on the first point of the loop
$extrusion_path->clip_end(scale $Slic3r::flow_width);
$extrusion_path->clip_end(scale $Slic3r::nozzle_diameter);

# extrude along the path
return $self->extrude($extrusion_path, $description);
Expand Down Expand Up @@ -118,16 +118,23 @@ sub extrude {
$gcode .= $self->unretract if $self->retracted;

# calculate extrusion length per distance unit
my $w = $path->flow_width || $Slic3r::flow_width;
my $s = $path->flow_spacing || $Slic3r::flow_spacing;
my $h = $path->depth_layers * $Slic3r::layer_height;
$h = $w if $path->role eq 'bridge';

# calculate additional flow for overlapping
my $overlap_area = $Slic3r::overlap_factor * (($Slic3r::layer_height**2) - ($Slic3r::layer_height**2) / 4 * PI);
$overlap_area = 0 if $path->role eq 'bridge';
my $w = ($s - $Slic3r::min_flow_spacing * $Slic3r::overlap_factor) / (1 - $Slic3r::overlap_factor);

my $area;
if ($path->role eq 'bridge') {
$area = ($s**2) * PI/4;
} elsif ($w >= ($Slic3r::nozzle_diameter + $h)) {
# rectangle with semicircles at the ends
$area = $w * $h + ($h**2) / 4 * (PI - 4);
} else {
# rectangle with shrunk semicircles at the ends
$area = $Slic3r::nozzle_diameter * $h * (1 - PI/4) + $h * $w * PI/4;
}

my $e = $Slic3r::resolution
* ($w * $h + ($Slic3r::layer_height**2) / 4 * (PI - 4) + $overlap_area)
* $area
* $Slic3r::extrusion_multiplier
* (4 / (($Slic3r::filament_diameter ** 2) * PI));

Expand Down
2 changes: 1 addition & 1 deletion lib/Slic3r/ExtrusionPath.pm
Expand Up @@ -7,7 +7,7 @@ extends 'Slic3r::Polyline';
# expressed in layers
has 'depth_layers' => (is => 'ro', default => sub {1});

has 'flow_width' => (is => 'rw');
has 'flow_spacing' => (is => 'rw');

# perimeter/fill/solid-fill/bridge/skirt
has 'role' => (is => 'rw', required => 1);
Expand Down
8 changes: 4 additions & 4 deletions lib/Slic3r/Fill.pm
Expand Up @@ -87,7 +87,7 @@ sub make_fill {
SURFACE: foreach my $surface (@surfaces) {
my $filler = $Slic3r::fill_pattern;
my $density = $Slic3r::fill_density;
my $flow_width = $Slic3r::flow_width;
my $flow_spacing = $Slic3r::flow_spacing;
my $is_bridge = $layer->id > 0 && $surface->surface_type eq 'bottom';
my $is_solid = $surface->surface_type =~ /^(top|bottom)$/;

Expand All @@ -97,7 +97,7 @@ sub make_fill {
$filler = $Slic3r::solid_fill_pattern;
if ($is_bridge) {
$filler = 'rectilinear';
$flow_width = sqrt($Slic3r::bridge_flow_ratio * ($Slic3r::nozzle_diameter**2));
$flow_spacing = sqrt($Slic3r::bridge_flow_ratio * ($Slic3r::nozzle_diameter**2));
} elsif ($surface->surface_type eq 'internal-solid') {
$filler = 'rectilinear';
}
Expand All @@ -108,7 +108,7 @@ sub make_fill {
my @paths = $self->fillers->{$filler}->fill_surface(
$surface,
density => $density,
flow_width => $flow_width,
flow_spacing => $flow_spacing,
);
my $params = shift @paths;

Expand All @@ -119,7 +119,7 @@ sub make_fill {
[ @$_ ],
role => ($is_bridge ? 'bridge' : $is_solid ? 'solid-fill' : 'fill'),
depth_layers => $surface->depth_layers,
flow_width => $params->{flow_width},
flow_spacing => $params->{flow_spacing},
), @paths,
],
) if @paths;
Expand Down
6 changes: 3 additions & 3 deletions lib/Slic3r/Fill/Concentric.pm
Expand Up @@ -12,8 +12,8 @@ sub fill_surface {

# no rotation is supported for this infill pattern

my $scaled_flow_width = scale $params{flow_width};
my $distance = $scaled_flow_width / $params{density};
my $scaled_flow_spacing = scale $params{flow_spacing};
my $distance = $scaled_flow_spacing / $params{density};
# TODO: adjust distance and flow width for solid surfaces
# using the same logic as Rectilinear infill
# (factor it out to parent class)
Expand Down Expand Up @@ -47,7 +47,7 @@ sub fill_surface {
my $path = $loop->split_at($cur_pos);

# clip the path to avoid the extruder to get exactly on the first point of the loop
$path->clip_end(scale $Slic3r::flow_width);
$path->clip_end(scale $Slic3r::nozzle_diameter);

push @paths, $path->p;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/Slic3r/Fill/PlanePath.pm
Expand Up @@ -27,7 +27,7 @@ sub fill_surface {
my $rotate_vector = $self->infill_direction($surface);
$self->rotate_points($expolygon, $rotate_vector);

my $distance_between_lines = scale $params{flow_width} / $params{density} * $self->multiplier;
my $distance_between_lines = scale $params{flow_spacing} / $params{density} * $self->multiplier;
my $bounding_box = [ bounding_box(map @$_, $expolygon) ];
my $bounding_box_polygon = Slic3r::Polygon->new([
[ $bounding_box->[X1], $bounding_box->[Y1] ],
Expand Down
10 changes: 5 additions & 5 deletions lib/Slic3r/Fill/Rectilinear.pm
Expand Up @@ -19,18 +19,18 @@ sub fill_surface {
$bounding_box->[X1] += scale 0.1;
$bounding_box->[X2] -= scale 0.1;

my $min_spacing = scale $params{flow_width};
my $min_spacing = scale $params{flow_spacing};
my $distance_between_lines = $min_spacing / $params{density};
my $line_oscillation = $distance_between_lines - $min_spacing;

my $number_of_lines = int(($bounding_box->[X2] - $bounding_box->[X1]) / $distance_between_lines) + 1;
my $flow_width = undef;
my $flow_spacing = undef;
if ($params{density} == 1) {
my $extra_space = ($bounding_box->[X2] - $bounding_box->[X1]) % $distance_between_lines;
$distance_between_lines += $extra_space / ($number_of_lines - 1) if $number_of_lines > 1;
$flow_width = unscale $distance_between_lines;
$flow_spacing = unscale $distance_between_lines;
}
my $overlap_distance = $min_spacing * $Slic3r::overlap_factor;
my $overlap_distance = $Slic3r::nozzle_diameter * 0.20;

my @paths = ();
my $x = $bounding_box->[X1];
Expand Down Expand Up @@ -79,7 +79,7 @@ sub fill_surface {
# paths must be rotated back
$self->rotate_points_back(\@paths, $rotate_vector);

return { flow_width => $flow_width }, @paths;
return { flow_spacing => $flow_spacing }, @paths;
}

1;
2 changes: 1 addition & 1 deletion lib/Slic3r/Fill/Rectilinear2.pm
Expand Up @@ -16,7 +16,7 @@ sub fill_surface {
my $rotate_vector = $self->infill_direction($surface);
$self->rotate_points($polygons, $rotate_vector);

my $distance_between_lines = scale $params{flow_width} / $params{density};
my $distance_between_lines = scale $params{flow_spacing} / $params{density};
my $number_of_lines = int(0.99999999 + $self->max_print_dimension / $distance_between_lines); # ceil

#printf "distance = %f\n", $distance_between_lines;
Expand Down
15 changes: 4 additions & 11 deletions lib/Slic3r/Layer.pm
Expand Up @@ -124,14 +124,7 @@ sub make_surfaces {

# the contours must be offsetted by half extrusion width inwards
{
my $distance = $Slic3r::flow_width / 2;
if ($Slic3r::overlap_factor) {
# our overlap is done by increasing the flow; however external perimeters will grow
# outwards, so we offset by the correct amount
$distance = ($Slic3r::flow_width + $Slic3r::overlap_factor * $Slic3r::layer_height * (1 - PI/4)) / 2;
}
$distance = scale $distance;

my $distance = scale $Slic3r::flow_width / 2;
my @surfaces = @{$self->slices};
@{$self->slices} = ();
foreach my $surface (@surfaces) {
Expand All @@ -156,7 +149,7 @@ sub prepare_fill_surfaces {
# merge too small internal surfaces with their surrounding tops
# (if they're too small, they can be treated as solid)
{
my $min_area = ((7 * $Slic3r::flow_width / $Slic3r::resolution)**2) * PI;
my $min_area = ((7 * $Slic3r::flow_spacing / $Slic3r::resolution)**2) * PI;
my $small_internal = [
grep { $_->expolygon->contour->area <= $min_area }
grep { $_->surface_type eq 'internal' }
Expand Down Expand Up @@ -189,7 +182,7 @@ sub prepare_fill_surfaces {
sub remove_small_surfaces {
my $self = shift;

my $distance = scale $Slic3r::flow_width / 2;
my $distance = scale $Slic3r::flow_spacing / 2;

my @surfaces = @{$self->fill_surfaces};
@{$self->fill_surfaces} = ();
Expand Down Expand Up @@ -257,7 +250,7 @@ sub process_bridges {
# offset the contour and intersect it with the internal surfaces to discover
# which of them has contact with our bridge
my @supporting_surfaces = ();
my ($contour_offset) = $expolygon->contour->offset(scale $Slic3r::flow_width * sqrt(2));
my ($contour_offset) = $expolygon->contour->offset(scale $Slic3r::flow_spacing * sqrt(2));
foreach my $internal_surface (@internal_surfaces) {
my $intersection = intersection_ex([$contour_offset], [$internal_surface->contour->p]);
if (@$intersection) {
Expand Down
2 changes: 1 addition & 1 deletion lib/Slic3r/Perimeter.pm
Expand Up @@ -45,7 +45,7 @@ sub make_perimeter {
push @{ $perimeters[-1] }, [@last_offsets];

# offset distance for inner loops
$distance = scale $Slic3r::flow_width;
$distance = scale $Slic3r::flow_spacing;
}

# create one more offset to be used as boundary for fill
Expand Down
2 changes: 1 addition & 1 deletion lib/Slic3r/Polyline/Closed.pm
Expand Up @@ -32,7 +32,7 @@ sub is_printable {
# if no offset is possible, then polyline is not printable
my $p = $self->p;
@$p = reverse @$p if !Math::Clipper::is_counter_clockwise($p);
my $offsets = Math::Clipper::offset([$p], -(scale $Slic3r::flow_width / 2), $Slic3r::resolution * 100000, JT_MITER, 2);
my $offsets = Math::Clipper::offset([$p], -(scale $Slic3r::flow_spacing / 2), $Slic3r::resolution * 100000, JT_MITER, 2);
return @$offsets ? 1 : 0;
}

Expand Down
2 changes: 1 addition & 1 deletion lib/Slic3r/Print.pm
Expand Up @@ -336,7 +336,7 @@ sub extrude_skirt {
# draw outlines from outside to inside
my @skirts = ();
for (my $i = $Slic3r::skirts - 1; $i >= 0; $i--) {
my $distance = scale ($Slic3r::skirt_distance + ($Slic3r::flow_width * $i));
my $distance = scale ($Slic3r::skirt_distance + ($Slic3r::flow_spacing * $i));
my $outline = offset([$convex_hull], $distance, $Slic3r::resolution * 100, JT_ROUND);
push @skirts, Slic3r::ExtrusionLoop->cast([ @{$outline->[0]} ], role => 'skirt');
}
Expand Down

0 comments on commit 1e6ecd9

Please sign in to comment.