diff --git a/lib/Slic3r/Config.pm b/lib/Slic3r/Config.pm index a1e862aa2..33500beff 100644 --- a/lib/Slic3r/Config.pm +++ b/lib/Slic3r/Config.pm @@ -725,8 +725,8 @@ sub validate { $Slic3r::support_material_flow = $Slic3r::extruders->[ $Slic3r::support_material_extruder-1 ] ->make_flow(width => $Slic3r::support_material_extrusion_width || $Slic3r::extrusion_width); - Slic3r::debugf "Default flow width = %s, spacing = %s, min_spacing = %s\n", - $Slic3r::flow->width, $Slic3r::flow->spacing, $Slic3r::flow->min_spacing; + Slic3r::debugf "Default flow width = %s (spacing = %s)\n", + $Slic3r::flow->width, $Slic3r::flow->spacing; # --perimeters die "Invalid value for --perimeters\n" diff --git a/lib/Slic3r/Extruder.pm b/lib/Slic3r/Extruder.pm index 8ab9c2790..07a0d0799 100644 --- a/lib/Slic3r/Extruder.pm +++ b/lib/Slic3r/Extruder.pm @@ -3,21 +3,18 @@ use Moo; use Slic3r::Geometry qw(PI); -has 'nozzle_diameter' => (is => 'rw', required => 1); -has 'filament_diameter' => (is => 'rw', required => 1); -has 'extrusion_multiplier' => (is => 'rw', required => 1); -has 'temperature' => (is => 'rw', required => 1); +has 'nozzle_diameter' => (is => 'ro', required => 1); +has 'filament_diameter' => (is => 'ro', required => 1); +has 'extrusion_multiplier' => (is => 'ro', required => 1); +has 'temperature' => (is => 'ro', required => 1); has 'first_layer_temperature' => (is => 'rw', required => 1); -has 'e_per_mm3' => (is => 'rw'); +has 'e_per_mm3' => (is => 'lazy'); +has '_mm3_per_mm_cache' => (is => 'ro', default => sub {{}}); -sub BUILD { +sub _build_e_per_mm3 { my $self = shift; - $self->e_per_mm3( - $Slic3r::scaling_factor - * $self->extrusion_multiplier - * (4 / (($self->filament_diameter ** 2) * PI)) - ); + return $self->extrusion_multiplier * (4 / (($self->filament_diameter ** 2) * PI)); } sub make_flow { @@ -25,4 +22,26 @@ sub make_flow { return Slic3r::Flow->new(nozzle_diameter => $self->nozzle_diameter, @_); } +sub mm3_per_mm { + my $self = shift; + my ($s, $h) = @_; + + my $cache_key = "${s}_${h}"; + if (!exists $self->_mm3_per_mm_cache->{$cache_key}) { + my $w_threshold = $h + $self->nozzle_diameter; + my $s_threshold = $w_threshold - $Slic3r::overlap_factor * ($w_threshold - ($w_threshold - $h * (1 - PI/4))); + + if ($s >= $s_threshold) { + # rectangle with semicircles at the ends + my $w = $s + $Slic3r::overlap_factor * $h * (1 - PI/4); + $self->_mm3_per_mm_cache->{$cache_key} = $w * $h + ($h**2) / 4 * (PI - 4); + } else { + # rectangle with shrunk semicircles at the ends + my $w = ($s + $self->nozzle_diameter * $Slic3r::overlap_factor * (PI/4 - 1)) / (1 + $Slic3r::overlap_factor * (PI/4 - 1)); + $self->_mm3_per_mm_cache->{$cache_key} = $self->nozzle_diameter * $h * (1 - PI/4) + $h * $w * PI/4; + } + } + return $self->_mm3_per_mm_cache->{$cache_key}; +} + 1; diff --git a/lib/Slic3r/Flow.pm b/lib/Slic3r/Flow.pm index f73fa7b22..959d6e3d3 100644 --- a/lib/Slic3r/Flow.pm +++ b/lib/Slic3r/Flow.pm @@ -3,53 +3,56 @@ use Moo; use Slic3r::Geometry qw(PI); -has 'nozzle_diameter' => (is => 'rw', required => 1); -has 'layer_height' => (is => 'rw', default => sub { $Slic3r::layer_height }); +has 'nozzle_diameter' => (is => 'ro', required => 1); +has 'layer_height' => (is => 'ro', default => sub { $Slic3r::layer_height }); -has 'width' => (is => 'rw'); -has 'min_spacing' => (is => 'rw'); -has 'spacing' => (is => 'rw'); +has 'width' => (is => 'rwp', builder => 1); +has 'spacing' => (is => 'lazy'); sub BUILD { my $self = shift; - my ($flow_width, $min_flow_spacing, $flow_spacing); - if ($self->width) { - $flow_width = $self->width =~ /^(\d+(?:\.\d+)?)%$/ - ? ($self->layer_height * $1 / 100) - : $self->width; + if ($self->width =~ /^(\d+(?:\.\d+)?)%$/) { + $self->_set_width($self->layer_height * $1 / 100); + } + $self->_set_width($self->_build_width) if $self->width == 0; # auto +} + +sub _build_width { + my $self = shift; + + # here we calculate a sane default by matching the flow speed (at the nozzle) and the feed rate + my $volume = ($self->nozzle_diameter**2) * PI/4; + my $shape_threshold = $self->nozzle_diameter * $self->layer_height + ($self->layer_height**2) * PI/4; + my $width; + if ($volume >= $shape_threshold) { + # rectangle with semicircles at the ends + $width = (($self->nozzle_diameter**2) * PI + ($self->layer_height**2) * (4 - PI)) / (4 * $self->layer_height); } else { - # here we calculate a sane default by matching the flow speed (at the nozzle) - # and the feed rate - my $volume = ($self->nozzle_diameter**2) * PI/4; - my $shape_threshold = $self->nozzle_diameter * $self->layer_height - + ($self->layer_height**2) * PI/4; - if ($volume >= $shape_threshold) { - # rectangle with semicircles at the ends - $flow_width = (($self->nozzle_diameter**2) * PI + ($self->layer_height**2) * (4 - PI)) / (4 * $self->layer_height); - } else { - # rectangle with squished semicircles at the ends - $flow_width = $self->nozzle_diameter * ($self->nozzle_diameter/$self->layer_height - 4/PI + 1); - } - - my $min_flow_width = $self->nozzle_diameter * 1.05; - my $max_flow_width = $self->nozzle_diameter * 1.4; - $flow_width = $max_flow_width if $flow_width > $max_flow_width; - $flow_width = $min_flow_width if $flow_width < $min_flow_width; + # rectangle with squished semicircles at the ends + $width = $self->nozzle_diameter * ($self->nozzle_diameter/$self->layer_height - 4/PI + 1); } - if ($flow_width >= ($self->nozzle_diameter + $self->layer_height)) { + my $min = $self->nozzle_diameter * 1.05; + my $max = $self->nozzle_diameter * 1.4; + $width = $max if $width > $max; + $width = $min if $width < $min; + + return $width; +} + +sub _build_spacing { + my $self = shift; + + my $min_flow_spacing; + if ($self->width >= ($self->nozzle_diameter + $self->layer_height)) { # rectangle with semicircles at the ends - $min_flow_spacing = $flow_width - $self->layer_height * (1 - PI/4); + $min_flow_spacing = $self->width - $self->layer_height * (1 - PI/4); } else { # rectangle with shrunk semicircles at the ends - $min_flow_spacing = $self->nozzle_diameter * (1 - PI/4) + $flow_width * PI/4; + $min_flow_spacing = $self->nozzle_diameter * (1 - PI/4) + $self->width * PI/4; } - $flow_spacing = $flow_width - $Slic3r::overlap_factor * ($flow_width - $min_flow_spacing); - - $self->width($flow_width); - $self->min_spacing($min_flow_spacing); - $self->spacing($flow_spacing); + return $self->width - $Slic3r::overlap_factor * ($self->width - $min_flow_spacing); } 1; diff --git a/lib/Slic3r/GCode.pm b/lib/Slic3r/GCode.pm index dcf6918b9..a7e0834d4 100644 --- a/lib/Slic3r/GCode.pm +++ b/lib/Slic3r/GCode.pm @@ -157,22 +157,17 @@ sub extrude_path { # compensate retraction $gcode .= $self->unretract if $self->retracted; - # calculate extrusion length per distance unit - my $s = $path->flow_spacing || ($self->layer ? $self->layer->flow->spacing : $Slic3r::flow->spacing); - my $h = $path->depth_layers * $self->layer->height; - my $w = ($s - ($self->layer ? $self->layer->flow->min_spacing : $Slic3r::flow->min_spacing) * $Slic3r::overlap_factor) / (1 - $Slic3r::overlap_factor); - - my $area; # = mm^3 of extrudate per mm of tool movement + my $area; # mm^3 of extrudate per mm of tool movement if ($path->role == EXTR_ROLE_BRIDGE) { + my $s = $path->flow_spacing || $self->extruder->nozzle_diameter; $area = ($s**2) * PI/4; - } elsif ($w >= ($self->extruder->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 = $self->extruder->nozzle_diameter * $h * (1 - PI/4) + $h * $w * PI/4; + my $s = $path->flow_spacing || ($self->layer ? $self->layer->flow->spacing : $Slic3r::flow->spacing); + my $h = $path->depth_layers * $self->layer->height; + $area = $self->extruder->mm3_per_mm($s, $h); } + # calculate extrusion length per distance unit my $e = $self->extruder->e_per_mm3 * $area; # extrude arc or line @@ -181,12 +176,12 @@ sub extrude_path { if ($path->isa('Slic3r::ExtrusionPath::Arc')) { $path_length = $path->length; $gcode .= $self->G2_G3($path->points->[-1], $path->orientation, - $path->center, $e * $path_length, $description); + $path->center, $e * unscale $path_length, $description); } else { foreach my $line ($path->lines) { my $line_length = $line->length; $path_length += $line_length; - $gcode .= $self->G1($line->b, undef, $e * $line_length, $description); + $gcode .= $self->G1($line->b, undef, $e * unscale $line_length, $description); } }