More incomplete work for Flow/Extruder refactoring

xs-bb
Alessandro Ranellucci 2014-01-03 18:27:46 +01:00
parent 52ce6e4a7b
commit 8ed738d3f7
27 changed files with 250 additions and 233 deletions

View File

@ -77,7 +77,6 @@ our $build = eval "use Slic3r::Build; 1";
use constant SCALING_FACTOR => 0.000001;
use constant RESOLUTION => 0.0125;
use constant SCALED_RESOLUTION => RESOLUTION / SCALING_FACTOR;
use constant OVERLAP_FACTOR => 1;
use constant SMALL_PERIMETER_LENGTH => (6.5 / SCALING_FACTOR) * 2 * PI;
use constant LOOP_CLIPPING_LENGTH_OVER_SPACING => 0.15;
use constant INFILL_OVERLAP_OVER_SPACING => 0.45;

View File

@ -26,13 +26,26 @@ has 'retracted' => (is => 'rw', default => sub {0} );
has 'restart_extra' => (is => 'rw', default => sub {0} );
has 'e_per_mm3' => (is => 'lazy');
has 'retract_speed_mm_min' => (is => 'lazy');
has '_mm3_per_mm_cache' => (is => 'ro', default => sub {{}});
use constant EXTRUDER_ROLE_PERIMETER => 1;
use constant EXTRUDER_ROLE_INFILL => 2;
use constant EXTRUDER_ROLE_SUPPORT_MATERIAL => 3;
use constant EXTRUDER_ROLE_SUPPORT_MATERIAL_INTERFACE => 4;
sub new_from_config {
my ($class, $config, $extruder_id) = @_;
my %conf = (
id => $extruder_id,
use_relative_e_distances => $config->use_relative_e_distances,
);
foreach my $opt_key (@{&OPTIONS}) {
my $value = $config->get($opt_key);
$conf{$opt_key} = $value->[$extruder_id] // $value->[0];
}
return $class->new(%conf);
}
sub _build_e_per_mm3 {
my $self = shift;
return $self->extrusion_multiplier * (4 / (($self->filament_diameter ** 2) * PI));
@ -43,6 +56,15 @@ sub _build_retract_speed_mm_min {
return $self->retract_speed * 60;
}
sub reset {
my ($self) = @_;
$self->E(0);
$self->absolute_E(0);
$self->retracted(0);
$self->restart_extra(0);
}
sub scaled_wipe_distance {
my ($self, $travel_speed) = @_;
@ -66,37 +88,9 @@ sub extruded_volume {
return $self->absolute_E * ($self->filament_diameter**2) * PI/4;
}
sub make_flow {
my $self = shift;
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};
}
sub e_per_mm {
my $self = shift;
my ($s, $h) = @_;
return $self->mm3_per_mm($s, $h) * $self->e_per_mm3;
my ($self, $mm3_per_mm) = @_;
return $mm3_per_mm * $self->e_per_mm3;
}
1;

View File

@ -8,8 +8,7 @@ sub split_at {
return Slic3r::ExtrusionPath->new(
polyline => $self->polygon->split_at(@_),
role => $self->role,
flow_spacing => $self->flow_spacing,
height => $self->height,
mm3_per_mm => $self->mm3_per_mm,
);
}

View File

@ -158,20 +158,17 @@ sub make_fill {
next SURFACE unless $density > 0;
}
my $flow_spacing = $flow->spacing;
my $f = $self->filler($filler);
$f->layer_id($layerm->id);
$f->angle($layerm->config->fill_angle);
my ($params, @polylines) = $f->fill_surface(
$surface,
density => $density,
flow_spacing => $flow_spacing,
density => $density,
flow => $flow,
);
next unless @polylines;
# ugly hack(tm) to get the right amount of flow (GCode.pm should be fixed)
$params->{flow_spacing} = $flow->width if $is_bridge;
my $mm3_per_mm = $params->{flow}->mm3_per_mm($surface->thickness);
# save into layer
push @fills, my $collection = Slic3r::ExtrusionPath::Collection->new;
@ -187,8 +184,7 @@ sub make_fill {
: $is_solid
? (($surface->surface_type == S_TYPE_TOP) ? EXTR_ROLE_TOPSOLIDFILL : EXTR_ROLE_SOLIDFILL)
: EXTR_ROLE_FILL),
height => $surface->thickness,
flow_spacing => $params->{flow_spacing} || (warn "Warning: no flow_spacing was returned by the infill engine, please report this to the developer\n"),
mm3_per_mm => $mm3_per_mm,
), @polylines,
);
push @fills_ordering_points, $polylines[0]->first_point;

View File

@ -17,11 +17,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}, $params{flow}->spacing;
my $m;
if (!($m = $self->cache->{$cache_id})) {
$m = $self->cache->{$cache_id} = {};
my $min_spacing = scale $params{flow_spacing};
my $min_spacing = $params{flow}->scaled_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);
@ -120,7 +120,7 @@ sub fill_surface {
)};
}
return { flow_spacing => $params{flow_spacing} }, @paths;
return { flow => $params{flow} }, @paths;
}
1;

View File

@ -17,8 +17,8 @@ sub fill_surface {
my $rotate_vector = $self->infill_direction($surface);
$self->rotate_points($expolygon, $rotate_vector);
my $flow_spacing = $params{flow_spacing};
my $min_spacing = scale $params{flow_spacing};
my $flow = $params{flow};
my $min_spacing = $flow->scaled_spacing;
my $line_spacing = $min_spacing / $params{density};
my $line_oscillation = $line_spacing - $min_spacing;
my $is_line_pattern = $self->isa('Slic3r::Fill::Line');
@ -30,7 +30,12 @@ sub fill_surface {
width => $bounding_box->size->[X],
distance => $line_spacing,
);
$flow_spacing = unscale $line_spacing;
$flow = Slic3r::Flow->new_from_spacing(
spacing => unscale($line_spacing),
nozzle_diameter => $flow->nozzle_diameter,
layer_height => $surface->thickness,
bridge => $flow->bridge,
);
} else {
# extend bounding box so that our pattern will be aligned with other layers
$bounding_box->extents->[X][MIN] -= $bounding_box->x_min % $line_spacing;
@ -62,7 +67,7 @@ sub fill_surface {
# connect lines
unless ($params{dont_connect} || !@polylines) { # prevent calling leftmost_point() on empty collections
my ($expolygon_off) = @{$expolygon->offset_ex(scale $params{flow_spacing}/2)};
my ($expolygon_off) = @{$expolygon->offset_ex($min_spacing/2)};
my $collection = Slic3r::Polyline::Collection->new(@polylines);
@polylines = ();
@ -97,7 +102,7 @@ sub fill_surface {
# paths must be rotated back
$self->rotate_points_back(\@polylines, $rotate_vector);
return { flow_spacing => $flow_spacing }, @polylines;
return { flow => $flow }, @polylines;
}
1;

View File

@ -9,8 +9,10 @@ our %EXPORT_TAGS = (roles => \@EXPORT_OK);
use Slic3r::Geometry qw(PI);
has 'width' => (is => 'ro');
has 'spacing' => (is => 'ro');
has 'width' => (is => 'ro', required => 1);
has 'spacing' => (is => 'ro', required => 1);
has 'nozzle_diameter' => (is => 'ro', required => 1);
has 'bridge' => (is => 'ro', default => sub {0});
has 'scaled_width' => (is => 'lazy');
has 'scaled_spacing' => (is => 'lazy');
@ -21,32 +23,67 @@ use constant FLOW_ROLE_TOP_SOLID_INFILL => 4;
use constant FLOW_ROLE_SUPPORT_MATERIAL => 5;
use constant FLOW_ROLE_SUPPORT_MATERIAL_INTERFACE => 6;
sub BUILDARGS {
my ($self, %args) = @_;
use constant BRIDGE_EXTRA_SPACING => 0.05;
use constant OVERLAP_FACTOR => 1;
sub new_from_width {
my ($class, %args) = @_;
# the constructor can take two sets of arguments:
# - width (only absolute value), spacing
# - width (abs/%/0), role, nozzle_diameter, layer_height, bridge_flow_ratio
# (if bridge_flow_ratio == 0, we return a non-bridge flow)
if (exists $args{role}) {
if ($args{width} eq '0') {
$args{width} = $self->_width(@args{qw(role nozzle_diameter layer_height bridge_flow_ratio)});
} elsif ($args{width} =~ /^(\d+(?:\.\d+)?)%$/) {
$args{width} = $args{layer_height} * $1 / 100;
}
$args{spacing} = $self->_spacing(@args{qw(width nozzle_diameter layer_height bridge_flow_ratio)});
%args = (
width => $args{width},
spacing => $args{spacing},
);
if ($args{width} eq '0') {
$args{width} = _width(@args{qw(role nozzle_diameter layer_height bridge_flow_ratio)});
} elsif ($args{width} =~ /^(\d+(?:\.\d+)?)%$/) {
$args{width} = $args{layer_height} * $1 / 100;
}
return {%args};
return $class->new(
width => $args{width},
spacing => _spacing(@args{qw(width nozzle_diameter layer_height bridge_flow_ratio)}),
nozzle_diameter => $args{nozzle_diameter},
bridge => ($args{bridge_flow_ratio} > 0) ? 1 : 0,
);
}
sub new_from_spacing {
my ($class, %args) = @_;
return $class->new(
width => _width_from_spacing(@args{qw(spacing nozzle_diameter layer_height bridge)}),
spacing => $args{spacing},
nozzle_diameter => $args{nozzle_diameter},
bridge => $args{bridge},
);
}
sub clone {
my $self = shift;
return (ref $self)->new(
width => $self->width,
spacing => $self->spacing,
nozzle_diameter => $self->nozzle_diameter,
bridge => $self->bridge,
);
}
sub mm3_per_mm {
my ($self, $h) = @_;
my $w = $self->width;
my $s = $self->spacing;
if ($self->bridge) {
return ($s**2) * PI/4;
} elsif ($w >= ($self->nozzle_diameter + $h)) {
# rectangle with semicircles at the ends
return $w * $h + ($h**2) / 4 * (PI - 4);
} else {
# rectangle with shrunk semicircles at the ends
return $self->nozzle_diameter * $h * (1 - PI/4) + $h * $w * PI/4;
}
}
sub _width {
my ($self, $role, $nozzle_diameter, $layer_height, $bridge_flow_ratio) = @_;
my ($role, $nozzle_diameter, $layer_height, $bridge_flow_ratio) = @_;
if ($bridge_flow_ratio > 0) {
return sqrt($bridge_flow_ratio * ($nozzle_diameter**2));
@ -78,11 +115,30 @@ sub _width {
return $width;
}
sub _width_from_spacing {
my ($s, $nozzle_diameter, $h, $bridge) = @_;
if ($bridge) {
return $s - BRIDGE_EXTRA_SPACING;
}
my $w_threshold = $h + $nozzle_diameter;
my $s_threshold = $w_threshold - OVERLAP_FACTOR * ($w_threshold - ($w_threshold - $h * (1 - PI/4)));
if ($s >= $s_threshold) {
# rectangle with semicircles at the ends
return $s + OVERLAP_FACTOR * $h * (1 - PI/4);
} else {
# rectangle with shrunk semicircles at the ends
return ($s + $nozzle_diameter * OVERLAP_FACTOR * (PI/4 - 1)) / (1 + OVERLAP_FACTOR * (PI/4 - 1));
}
}
sub _spacing {
my ($self, $width, $nozzle_diameter, $layer_height, $bridge_flow_ratio) = @_;
my ($width, $nozzle_diameter, $layer_height, $bridge_flow_ratio) = @_;
if ($bridge_flow_ratio > 0) {
return $width + 0.05;
return $width + BRIDGE_EXTRA_SPACING;
}
my $min_flow_spacing;
@ -93,16 +149,7 @@ sub _spacing {
# rectangle with shrunk semicircles at the ends
$min_flow_spacing = $nozzle_diameter * (1 - PI/4) + $width * PI/4;
}
return $width - &Slic3r::OVERLAP_FACTOR * ($width - $min_flow_spacing);
}
sub clone {
my $self = shift;
return (ref $self)->new(
width => $self->width,
spacing => $self->spacing,
);
return $width - OVERLAP_FACTOR * ($width - $min_flow_spacing);
}
sub _build_scaled_width {

View File

@ -10,8 +10,6 @@ use Slic3r::Surface ':types';
has 'print_config' => (is => 'ro', default => sub { Slic3r::Config::Print->new });
has 'extra_variables' => (is => 'rw', default => sub {{}});
has 'extruders' => (is => 'ro', required => 1);
has 'multiple_extruders' => (is => 'lazy');
has 'standby_points' => (is => 'rw');
has 'enable_loop_clipping' => (is => 'rw', default => sub {1});
has 'enable_wipe' => (is => 'lazy'); # at least one extruder has wipe enabled
@ -27,6 +25,7 @@ has 'z' => (is => 'rw');
has 'speed' => (is => 'rw');
has '_extrusion_axis' => (is => 'rw');
has '_retract_lift' => (is => 'rw');
has 'extruders' => (is => 'ro', default => sub {[]});
has 'speeds' => (is => 'lazy'); # mm/min
has 'external_mp' => (is => 'rw');
@ -49,6 +48,14 @@ sub BUILD {
$self->_retract_lift($self->print_config->retract_lift->[0]);
}
sub set_extruders {
my ($self, $extruder_ids) = @_;
foreach my $i (@$extruder_ids) {
$self->extruders->[$i] = Slic3r::Extruder->new_from_config($self->print_config, $i);
}
}
sub _build_speeds {
my $self = shift;
return {
@ -73,7 +80,7 @@ my %role_speeds = (
&EXTR_ROLE_GAPFILL => 'gap_fill',
);
sub _build_multiple_extruders {
sub multiple_extruders {
my $self = shift;
return @{$self->extruders} > 1;
}
@ -320,18 +327,8 @@ sub extrude_path {
$gcode .= $self->set_acceleration($acceleration) if $acceleration;
}
my $area; # mm^3 of extrudate per mm of tool movement
if ($path->is_bridge) {
my $s = $path->flow_spacing;
$area = ($s**2) * PI/4;
} else {
my $s = $path->flow_spacing;
my $h = (defined $path->height && $path->height != -1) ? $path->height : $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;
my $e = $self->extruder->e_per_mm3 * $path->mm3_per_mm;
$e = 0 if !$self->_extrusion_axis;
# set speed
@ -640,14 +637,14 @@ sub _Gx {
}
sub set_extruder {
my ($self, $extruder) = @_;
my ($self, $extruder_id) = @_;
# return nothing if this extruder was already selected
return "" if (defined $self->extruder) && ($self->extruder->id == $extruder->id);
return "" if (defined $self->extruder) && ($self->extruder->id == $extruder_id);
# if we are running a single-extruder setup, just set the extruder and return nothing
if (!$self->multiple_extruders) {
$self->extruder($extruder);
$self->extruder($self->extruders->[$extruder_id]);
return "";
}
@ -659,7 +656,7 @@ sub set_extruder {
if (defined $self->extruder && $self->print_config->toolchange_gcode) {
$gcode .= sprintf "%s\n", $self->replace_variables($self->print_config->toolchange_gcode, {
previous_extruder => $self->extruder->id,
next_extruder => $extruder->id,
next_extruder => $extruder_id,
});
}
@ -676,14 +673,14 @@ sub set_extruder {
}
# set the new extruder
$self->extruder($extruder);
$self->extruder($self->extruders->[$extruder_id]);
$gcode .= sprintf "%s%d%s\n",
($self->print_config->gcode_flavor eq 'makerware'
? 'M135 T'
: $self->print_config->gcode_flavor eq 'sailfish'
? 'M108 T'
: 'T'),
$extruder->id,
$extruder_id,
($self->print_config->gcode_comments ? ' ; change extruder' : '');
$gcode .= $self->reset_e;

View File

@ -85,7 +85,7 @@ sub process_layer {
# when printing layers > 0 ignore 'min_skirt_length' and
# just use the 'skirts' setting; also just use the current extruder
last if ($layer->id > 0) && ($i >= $self->print->config->skirts);
$gcode .= $self->gcodegen->set_extruder($self->extruders->[ ($i/@{$self->extruders}) % @{$self->extruders} ])
$gcode .= $self->gcodegen->set_extruder(($i/@{$self->extruders}) % @{$self->extruders})
if $layer->id == 0;
$gcode .= $self->gcodegen->extrude_loop($skirt_loops[$i], 'skirt');
}
@ -96,7 +96,7 @@ sub process_layer {
# extrude brim
if (!$self->brim_done) {
$gcode .= $self->gcodegen->set_extruder($self->extruders->[$self->print->objects->[0]->config->support_material_extruder-1]);
$gcode .= $self->gcodegen->set_extruder($self->print->objects->[0]->config->support_material_extruder-1);
$self->gcodegen->set_shift(@{$self->shift});
$gcode .= $self->gcodegen->extrude_loop($_, 'brim') for @{$self->print->brim};
$self->brim_done(1);
@ -113,13 +113,13 @@ sub process_layer {
# and also because we avoid travelling on other things when printing it
if ($layer->isa('Slic3r::Layer::Support')) {
if ($layer->support_interface_fills->count > 0) {
$gcode .= $self->gcodegen->set_extruder($self->extruders->[$object->config->support_material_interface_extruder-1]);
$gcode .= $self->gcodegen->set_extruder($object->config->support_material_interface_extruder-1);
my %params = (speed => $object->config->support_material_speed*60);
$gcode .= $self->gcodegen->extrude_path($_, 'support material interface', %params)
for @{$layer->support_interface_fills->chained_path_from($self->gcodegen->last_pos, 0)};
}
if ($layer->support_fills->count > 0) {
$gcode .= $self->gcodegen->set_extruder($self->extruders->[$object->config->support_material_extruder-1]);
$gcode .= $self->gcodegen->set_extruder($object->config->support_material_extruder-1);
my %params = (speed => $object->config->support_material_speed*60);
$gcode .= $self->gcodegen->extrude_path($_, 'support material', %params)
for @{$layer->support_fills->chained_path_from($self->gcodegen->last_pos, 0)};
@ -205,7 +205,7 @@ sub _extrude_perimeters {
return "" if !@{ $island->{perimeters} };
my $gcode = "";
$gcode .= $self->gcodegen->set_extruder($self->extruders->[$region->config->perimeter_extruder-1]);
$gcode .= $self->gcodegen->set_extruder($region->config->perimeter_extruder-1);
$gcode .= $self->gcodegen->extrude($_, 'perimeter') for @{ $island->{perimeters} };
return $gcode;
}
@ -217,7 +217,7 @@ sub _extrude_infill {
return "" if !@{ $island->{fills} };
my $gcode = "";
$gcode .= $self->gcodegen->set_extruder($self->extruders->[$region->config->infill_extruder-1]);
$gcode .= $self->gcodegen->set_extruder($region->config->infill_extruder-1);
for my $fill (@{ $island->{fills} }) {
if ($fill->isa('Slic3r::ExtrusionPath::Collection')) {
$gcode .= $self->gcodegen->extrude($_, 'fill')

View File

@ -125,6 +125,7 @@ sub make_perimeters {
my $self = shift;
my $perimeter_flow = $self->flow(FLOW_ROLE_PERIMETER);
my $mm3_per_mm = $perimeter_flow->mm3_per_mm($self->height);
my $pwidth = $perimeter_flow->scaled_width;
my $pspacing = $perimeter_flow->scaled_spacing;
my $ispacing = $self->flow(FLOW_ROLE_SOLID_INFILL)->scaled_spacing;
@ -264,7 +265,7 @@ sub make_perimeters {
push @loops, Slic3r::ExtrusionLoop->new(
polygon => $polygon,
role => $role,
flow_spacing => $perimeter_flow->spacing,
mm3_per_mm => $mm3_per_mm,
);
}
return @loops;
@ -290,8 +291,8 @@ sub make_perimeters {
for my $p (@p) {
next if $p->length <= $pspacing * 2;
my %params = (
role => EXTR_ROLE_EXTERNAL_PERIMETER,
flow_spacing => $perimeter_flow->spacing,
role => EXTR_ROLE_EXTERNAL_PERIMETER,
mm3_per_mm => $mm3_per_mm,
);
push @paths, $p->isa('Slic3r::Polygon')
? Slic3r::ExtrusionLoop->new(polygon => $p, %params)
@ -339,8 +340,8 @@ sub _fill_gaps {
# fill gaps using dynamic extrusion width, by treating them like thin polygons,
# thus generating the skeleton and using it to fill them
my %path_args = (
role => EXTR_ROLE_SOLIDFILL,
flow_spacing => $flow->spacing,
role => EXTR_ROLE_SOLIDFILL,
mm3_per_mm => $flow->mm3_per_mm($self->height),
);
$self->thin_fills->append(map {
$_->isa('Slic3r::Polygon')
@ -360,9 +361,10 @@ sub _fill_gaps {
foreach my $expolygon (@infill) {
my ($params, @paths) = $filler->fill_surface(
Slic3r::Surface->new(expolygon => $expolygon, surface_type => S_TYPE_INTERNALSOLID),
density => 1,
flow_spacing => $flow->spacing,
density => 1,
flow => $flow,
);
my $mm3_per_mm = $params->{flow}->mm3_per_mm($self->height);
# Split polylines into lines so that the chained_path() search
# at the final stage has more freedom and will choose starting
@ -379,8 +381,7 @@ sub _fill_gaps {
@paths = map Slic3r::ExtrusionPath->new(
polyline => Slic3r::Polyline->new(@$_),
role => EXTR_ROLE_GAPFILL,
height => $self->height,
flow_spacing => $params->{flow_spacing},
mm3_per_mm => $mm3_per_mm,
), @lines;
$_->simplify($flow->scaled_width/3) for @paths;

View File

@ -305,26 +305,6 @@ sub extruders {
sub init_extruders {
my $self = shift;
# initialize all extruder(s) we need
for my $extruder_id (@{$self->extruders}) {
# make sure print config contains a value for all extruders
my %extruder_config = ();
foreach my $opt_key (@{&Slic3r::Extruder::OPTIONS}) {
my $value = $self->config->get($opt_key);
if (!defined $value->[$extruder_id]) {
$value->[$extruder_id] = $value->[0];
$self->config->set($opt_key, $value);
}
$extruder_config{$opt_key} = $value->[$extruder_id];
}
$self->extruders->[$extruder_id] = Slic3r::Extruder->new(
id => $extruder_id,
use_relative_e_distances => $self->config->use_relative_e_distances,
%extruder_config,
);
}
# enforce tall skirt if using ooze_prevention
# FIXME: this is not idempotent (i.e. switching ooze_prevention off will not revert skirt settings)
if ($self->config->ooze_prevention && @{$self->extruders} > 1) {
@ -671,7 +651,7 @@ sub make_skirt {
# but loops must be aligned so can't vary width/spacing
# TODO: use each extruder's own flow
my $first_layer_height = $self->objects->[0]->config->get_value('first_layer_height');
my $flow = Slic3r::Flow->new(
my $flow = Slic3r::Flow->new_from_width(
width => ($self->config->first_layer_extrusion_width || $self->regions->[0]->config->perimeter_extrusion_width),
role => FLOW_ROLE_PERIMETER,
nozzle_diameter => $self->config->nozzle_diameter->[0],
@ -679,6 +659,7 @@ sub make_skirt {
bridge_flow_ratio => 0,
);
my $spacing = $flow->spacing;
my $mm3_per_mm = $flow->mm3_per_mm($first_layer_height);
my @extruders_e_per_mm = ();
my $extruder_idx = 0;
@ -692,13 +673,16 @@ sub make_skirt {
$self->skirt->append(Slic3r::ExtrusionLoop->new(
polygon => Slic3r::Polygon->new(@$loop),
role => EXTR_ROLE_SKIRT,
flow_spacing => $spacing,
mm3_per_mm => $mm3_per_mm,
));
if ($self->config->min_skirt_length > 0) {
$extruded_length[$extruder_idx] ||= 0;
$extruders_e_per_mm[$extruder_idx] ||= $self->extruders->[$extruder_idx]->e_per_mm($spacing, $first_layer_height);
$extruded_length[$extruder_idx] += unscale $loop->length * $extruders_e_per_mm[$extruder_idx];
$extruded_length[$extruder_idx] ||= 0;
if (!$extruders_e_per_mm[$extruder_idx]) {
my $extruder = Slic3r::Extruder->new_from_config($self->config, $extruder_idx);
$extruders_e_per_mm[$extruder_idx] = $extruder->e_per_mm($mm3_per_mm);
}
$extruded_length[$extruder_idx] += unscale $loop->length * $extruders_e_per_mm[$extruder_idx];
$i++ if defined first { ($extruded_length[$_] // 0) < $self->config->min_skirt_length } 0 .. $#{$self->extruders};
if ($extruded_length[$extruder_idx] >= $self->config->min_skirt_length) {
if ($extruder_idx < $#{$self->extruders}) {
@ -719,13 +703,15 @@ sub make_brim {
$self->brim->clear; # method must be idempotent
# brim is only printed on first layer and uses support material extruder
my $flow = Slic3r::Flow->new(
my $first_layer_height = $self->objects->[0]->config->get_abs_value('first_layer_height');
my $flow = Slic3r::Flow->new_from_width(
width => ($self->config->first_layer_extrusion_width || $self->regions->[0]->config->perimeter_extrusion_width),
role => FLOW_ROLE_PERIMETER,
nozzle_diameter => $self->config->nozzle_diameter->[ $self->objects->[0]->config->support_material_extruder-1 ],
layer_height => $self->objects->[0]->config->get_abs_value('first_layer_height'),
layer_height => $first_layer_height,
bridge_flow_ratio => 0,
);
my $mm3_per_mm = $flow->mm3_per_mm($first_layer_height);
my $grow_distance = $flow->scaled_width / 2;
my @islands = (); # array of polygons
@ -768,7 +754,7 @@ sub make_brim {
$self->brim->append(map Slic3r::ExtrusionLoop->new(
polygon => Slic3r::Polygon->new(@$_),
role => EXTR_ROLE_SKIRT,
flow_spacing => $flow->spacing,
mm3_per_mm => $mm3_per_mm,
), reverse @{union_pt_chained(\@loops)});
}
@ -816,9 +802,11 @@ sub write_gcode {
my $gcodegen = Slic3r::GCode->new(
print_config => $self->config,
extra_variables => $self->extra_variables,
extruders => $self->extruders, # we should only pass the *used* extruders (but maintain the Tx indices right!)
layer_count => $self->layer_count,
);
$gcodegen->set_extruders($self->extruders);
$gcodegen->set_extruder($self->extruders->[0]);
print $fh "G21 ; set units to millimeters\n" if $self->config->gcode_flavor ne 'makerware';
print $fh $gcodegen->set_fan(0, 1) if $self->config->cooling && $self->config->disable_fan_first_layers;
@ -833,7 +821,7 @@ sub write_gcode {
return if $self->config->start_gcode =~ /M(?:109|104)/i;
for my $t (0 .. $#{$self->extruders}) {
my $temp = $self->extruders->[$t]->first_layer_temperature;
my $temp = $self->config->first_layer_temperature->[$t] // $self->config->first_layer_temperature->[0];
$temp += $self->config->standby_temperature_delta if $self->config->ooze_prevention;
printf $fh $gcodegen->set_temperature($temp, $wait, $t) if $temp > 0;
}

View File

@ -863,7 +863,7 @@ sub generate_support_material {
return unless ($self->config->support_material || $self->config->raft_layers > 0)
&& $self->layer_count >= 2;
my $first_layer_flow = Slic3r::Flow->new(
my $first_layer_flow = Slic3r::Flow->new_from_width(
width => ($self->config->first_layer_extrusion_width || $self->config->support_material_extrusion_width),
role => FLOW_ROLE_SUPPORT_MATERIAL,
nozzle_diameter => $self->print->config->nozzle_diameter->[ $self->config->support_material_extruder-1 ],
@ -900,7 +900,7 @@ sub support_material_flow {
# we use a bogus layer_height because we use the same flow for all
# support material layers
return Slic3r::Flow->new(
return Slic3r::Flow->new_from_width(
width => $self->config->support_material_extrusion_width,
role => $role,
nozzle_diameter => $self->print->config->nozzle_diameter->[$extruder-1],

View File

@ -48,7 +48,7 @@ sub flow {
}
my $nozzle_diameter = $self->print->config->nozzle_diameter->[$extruder-1];
return Slic3r::Flow->new(
return Slic3r::Flow->new_from_width(
width => $config_width,
role => $role,
nozzle_diameter => $nozzle_diameter,

View File

@ -500,10 +500,11 @@ sub generate_toolpaths {
);
# transform loops into ExtrusionPath objects
my $mm3_per_mm = $interface_flow->mm3_per_mm($layer->height);
@loops = map Slic3r::ExtrusionPath->new(
polyline => $_,
role => EXTR_ROLE_SUPPORTMATERIAL,
flow_spacing => $interface_flow->spacing,
polyline => $_,
role => EXTR_ROLE_SUPPORTMATERIAL,
mm3_per_mm => $mm3_per_mm,
), @loops;
$layer->support_interface_fills->append(@loops);
@ -536,16 +537,16 @@ sub generate_toolpaths {
foreach my $expolygon (@{union_ex($interface)}) {
my ($params, @p) = $fillers{interface}->fill_surface(
Slic3r::Surface->new(expolygon => $expolygon, surface_type => S_TYPE_INTERNAL),
density => $interface_density,
flow_spacing => $interface_flow->spacing,
complete => 1,
density => $interface_density,
flow => $interface_flow,
complete => 1,
);
my $mm3_per_mm = $params->{flow}->mm3_per_mm($layer->height);
push @paths, map Slic3r::ExtrusionPath->new(
polyline => Slic3r::Polyline->new(@$_),
role => EXTR_ROLE_SUPPORTMATERIAL,
height => undef,
flow_spacing => $params->{flow_spacing},
polyline => Slic3r::Polyline->new(@$_),
role => EXTR_ROLE_SUPPORTMATERIAL,
mm3_per_mm => $mm3_per_mm,
), @p;
}
@ -556,8 +557,8 @@ sub generate_toolpaths {
if (@$base) {
my $filler = $fillers{support};
$filler->angle($angles[ ($layer_id) % @angles ]);
my $density = $support_density;
my $flow_spacing = $flow->spacing;
my $density = $support_density;
my $base_flow = $flow;
# TODO: use offset2_ex()
my $to_infill = union_ex($base, 1);
@ -568,15 +569,15 @@ sub generate_toolpaths {
$filler = $fillers{interface};
$filler->angle($self->object_config->support_material_angle + 90);
$density = 0.5;
$flow_spacing = $self->first_layer_flow->spacing;
$base_flow = $self->first_layer_flow;
} else {
# draw a perimeter all around support infill
# TODO: use brim ordering algorithm
my $mm3_per_mm = $flow->mm3_per_mm($layer->height);
push @paths, map Slic3r::ExtrusionPath->new(
polyline => $_->split_at_first_point,
role => EXTR_ROLE_SUPPORTMATERIAL,
height => undef,
flow_spacing => $flow->spacing,
polyline => $_->split_at_first_point,
role => EXTR_ROLE_SUPPORTMATERIAL,
mm3_per_mm => $mm3_per_mm,
), map @$_, @$to_infill;
# TODO: use offset2_ex()
@ -586,16 +587,16 @@ sub generate_toolpaths {
foreach my $expolygon (@$to_infill) {
my ($params, @p) = $filler->fill_surface(
Slic3r::Surface->new(expolygon => $expolygon, surface_type => S_TYPE_INTERNAL),
density => $density,
flow_spacing => $flow_spacing,
complete => 1,
density => $density,
flow => $base_flow,
complete => 1,
);
my $mm3_per_mm = $params->{flow}->mm3_per_mm($layer->height);
push @paths, map Slic3r::ExtrusionPath->new(
polyline => Slic3r::Polyline->new(@$_),
role => EXTR_ROLE_SUPPORTMATERIAL,
height => undef,
flow_spacing => $params->{flow_spacing},
polyline => Slic3r::Polyline->new(@$_),
role => EXTR_ROLE_SUPPORTMATERIAL,
mm3_per_mm => $mm3_per_mm,
), @p;
}

View File

@ -21,7 +21,7 @@ use Slic3r::Geometry qw(scaled_epsilon scale X Y);
[306517.1,219034.23], [286979.42,248012.49], [258001.16,267550.17], [222515.14,274714.47],
[187029.11,267550.17], [158050.85,248012.49], [138513.17,219034.23], [131348.87,183548.2],
[86948.77,175149.09], [119825.35,100585],
), role => EXTR_ROLE_FILL, flow_spacing => 0.5);
), role => EXTR_ROLE_FILL, mm3_per_mm => 0.5);
my @paths = $path->detect_arcs(30);
@ -42,12 +42,12 @@ use Slic3r::Geometry qw(scaled_epsilon scale X Y);
my $path1 = Slic3r::ExtrusionPath->new(
polyline => Slic3r::Polyline->new(@points),
role => EXTR_ROLE_FILL,
flow_spacing => 0.5,
mm3_per_mm => 0.5,
);
my $path2 = Slic3r::ExtrusionPath->new(
polyline => Slic3r::Polyline->new(reverse @points),
role => EXTR_ROLE_FILL,
flow_spacing => 0.5,
mm3_per_mm => 0.5,
);
my @paths1 = $path1->detect_arcs(10, scale 1);

View File

@ -134,7 +134,7 @@ sub scale_points (@) { map [scale $_->[X], scale $_->[Y]], @_ }
{
my $collection = Slic3r::ExtrusionPath::Collection->new(
map Slic3r::ExtrusionPath->new(polyline => $_, role => 0),
map Slic3r::ExtrusionPath->new(polyline => $_, role => 0, mm3_per_mm => 1),
Slic3r::Polyline->new([0,15], [0,18], [0,20]),
Slic3r::Polyline->new([0,10], [0,8], [0,5]),
);
@ -146,7 +146,7 @@ sub scale_points (@) { map [scale $_->[X], scale $_->[Y]], @_ }
{
my $collection = Slic3r::ExtrusionPath::Collection->new(
map Slic3r::ExtrusionPath->new(polyline => $_, role => 0),
map Slic3r::ExtrusionPath->new(polyline => $_, role => 0, mm3_per_mm => 1),
Slic3r::Polyline->new([15,0], [10,0], [4,0]),
Slic3r::Polyline->new([10,5], [15,5], [20,5]),
);

View File

@ -97,8 +97,7 @@ sub new {
return $class->_new(
$args{polygon}, # required
$args{role}, # required
$args{height} // -1,
$args{flow_spacing} // -1,
$args{mm3_per_mm} // -1,
);
}
@ -108,8 +107,7 @@ sub clone {
return (ref $self)->_new(
$args{polygon} // $self->polygon,
$args{role} // $self->role,
$args{height} // $self->height,
$args{flow_spacing} // $self->flow_spacing,
$args{mm3_per_mm} // $self->mm3_per_mm,
);
}
@ -129,8 +127,7 @@ sub new {
return $class->_new(
$args{polyline}, # required
$args{role}, # required
$args{height} // -1,
$args{flow_spacing} // -1,
$args{mm3_per_mm} // -1,
);
}
@ -140,8 +137,7 @@ sub clone {
return (ref $self)->_new(
$args{polyline} // $self->polyline,
$args{role} // $self->role,
$args{height} // $self->height,
$args{flow_spacing} // $self->flow_spacing,
$args{mm3_per_mm} // $self->mm3_per_mm,
);
}

View File

@ -116,8 +116,7 @@ ExtrusionLoop::split_at_index(int index) const
ExtrusionPath* path = new ExtrusionPath();
path->polyline = *poly;
path->role = this->role;
path->height = this->height;
path->flow_spacing = this->flow_spacing;
path->mm3_per_mm = this->mm3_per_mm;
delete poly;
return path;

View File

@ -31,8 +31,7 @@ class ExtrusionEntity
virtual ExtrusionEntity* clone() const = 0;
virtual ~ExtrusionEntity() {};
ExtrusionRole role;
double height; // vertical thickness of the extrusion expressed in mm
double flow_spacing;
double mm3_per_mm; // mm^3 of plastic per mm of linear head motion
virtual void reverse() = 0;
virtual Point* first_point() const = 0;
virtual Point* last_point() const = 0;

View File

@ -241,6 +241,7 @@ class PrintConfigDef
Options["fill_pattern"].tooltip = "Fill pattern for general low-density infill.";
Options["fill_pattern"].cli = "fill-pattern=s";
Options["fill_pattern"].scope = "object";
Options["fill_pattern"].enum_keys_map = ConfigOptionEnum<InfillPattern>::get_enum_values();
Options["fill_pattern"].enum_values.push_back("rectilinear");
Options["fill_pattern"].enum_values.push_back("line");
Options["fill_pattern"].enum_values.push_back("concentric");
@ -320,6 +321,7 @@ class PrintConfigDef
Options["gcode_flavor"].label = "G-code flavor";
Options["gcode_flavor"].tooltip = "Some G/M-code commands, including temperature control and others, are not universal. Set this option to your printer's firmware to get a compatible output. The \"No extrusion\" flavor prevents Slic3r from exporting any extrusion value at all.";
Options["gcode_flavor"].cli = "gcode-flavor=s";
Options["gcode_flavor"].enum_keys_map = ConfigOptionEnum<GCodeFlavor>::get_enum_values();
Options["gcode_flavor"].enum_values.push_back("reprap");
Options["gcode_flavor"].enum_values.push_back("teacup");
Options["gcode_flavor"].enum_values.push_back("makerware");
@ -613,6 +615,7 @@ class PrintConfigDef
Options["solid_fill_pattern"].tooltip = "Fill pattern for top/bottom infill.";
Options["solid_fill_pattern"].cli = "solid-fill-pattern=s";
Options["solid_fill_pattern"].scope = "object";
Options["solid_fill_pattern"].enum_keys_map = ConfigOptionEnum<InfillPattern>::get_enum_values();
Options["solid_fill_pattern"].enum_values.push_back("rectilinear");
Options["solid_fill_pattern"].enum_values.push_back("concentric");
Options["solid_fill_pattern"].enum_values.push_back("hilbertcurve");

View File

@ -15,6 +15,7 @@ my $points = [
my $path = Slic3r::ExtrusionPath->new(
polyline => Slic3r::Polyline->new(@$points),
role => Slic3r::ExtrusionPath::EXTR_ROLE_EXTERNAL_PERIMETER,
mm3_per_mm => 1,
);
isa_ok $path->polyline, 'Slic3r::Polyline::Ref', 'path polyline';
is_deeply $path->polyline->pp, $points, 'path points roundtrip';

View File

@ -16,6 +16,7 @@ my $square = [
my $loop = Slic3r::ExtrusionLoop->new(
polygon => Slic3r::Polygon->new(@$square),
role => Slic3r::ExtrusionPath::EXTR_ROLE_EXTERNAL_PERIMETER,
mm3_per_mm => 1,
);
isa_ok $loop->polygon, 'Slic3r::Polygon::Ref', 'loop polygon';
is_deeply $loop->polygon->pp, $square, 'polygon points roundtrip';

View File

@ -15,11 +15,13 @@ my $points = [
my $path = Slic3r::ExtrusionPath->new(
polyline => Slic3r::Polyline->new(@$points),
role => Slic3r::ExtrusionPath::EXTR_ROLE_EXTERNAL_PERIMETER,
mm3_per_mm => 1,
);
my $loop = Slic3r::ExtrusionLoop->new(
polygon => Slic3r::Polygon->new(@$points),
role => Slic3r::ExtrusionPath::EXTR_ROLE_FILL,
mm3_per_mm => 1,
);
my $collection = Slic3r::ExtrusionPath::Collection->new($path);
@ -49,7 +51,7 @@ is scalar(@{$collection->[1]}), 1, 'appended collection was duplicated';
{
my $collection = Slic3r::ExtrusionPath::Collection->new(
map Slic3r::ExtrusionPath->new(polyline => $_, role => 0),
map Slic3r::ExtrusionPath->new(polyline => $_, role => 0, mm3_per_mm => 1),
Slic3r::Polyline->new([0,15], [0,18], [0,20]),
Slic3r::Polyline->new([0,10], [0,8], [0,5]),
);
@ -65,7 +67,7 @@ is scalar(@{$collection->[1]}), 1, 'appended collection was duplicated';
{
my $collection = Slic3r::ExtrusionPath::Collection->new(
map Slic3r::ExtrusionPath->new(polyline => $_, role => 0),
map Slic3r::ExtrusionPath->new(polyline => $_, role => 0, mm3_per_mm => 1),
Slic3r::Polyline->new([15,0], [10,0], [4,0]),
Slic3r::Polyline->new([10,5], [15,5], [20,5]),
);

View File

@ -4,7 +4,7 @@ use strict;
use warnings;
use Slic3r::XS;
use Test::More tests => 79;
use Test::More tests => 82;
foreach my $config (Slic3r::Config->new, Slic3r::Config::Full->new) {
$config->set('layer_height', 0.3);
@ -49,6 +49,9 @@ foreach my $config (Slic3r::Config->new, Slic3r::Config::Full->new) {
$config->set_deserialize('gcode_flavor', 'mach3');
is $config->get('gcode_flavor'), 'mach3', 'deserialize enum';
$config->set_deserialize('fill_pattern', 'line');
is $config->get('fill_pattern'), 'line', 'deserialize enum';
$config->set('extruder_offset', [[10,20],[30,45]]);
is_deeply $config->get('extruder_offset'), [[10,20],[30,45]], 'set/get points';
is $config->serialize('extruder_offset'), '10x20,30x45', 'serialize points';
@ -106,4 +109,14 @@ foreach my $config (Slic3r::Config->new, Slic3r::Config::Full->new) {
is $config2->get('perimeters'), Slic3r::Config::print_config_def()->{perimeters}{default}, 'apply_static and print_config_def';
}
{
my $config = Slic3r::Config->new;
$config->set('fill_pattern', 'line');
my $config2 = Slic3r::Config->new;
$config2->set('fill_pattern', 'hilbertcurve');
is $config->get('fill_pattern'), 'line', 'no interferences between DynamicConfig objects';
}
__END__

View File

@ -19,7 +19,7 @@
double get_abs_value(t_config_option_key opt_key, double ratio_over);
void apply(DynamicPrintConfig* other)
%code{% THIS->apply(*other, true); %};
void apply_static(PrintConfig* other)
void apply_static(FullPrintConfig* other)
%code{% THIS->apply(*other, true); %};
std::vector<std::string> get_keys()
%code{% THIS->keys(&RETVAL); %};

View File

@ -28,18 +28,16 @@
%{
ExtrusionLoop*
_new(CLASS, polygon_sv, role, height, flow_spacing)
_new(CLASS, polygon_sv, role, mm3_per_mm)
char* CLASS;
SV* polygon_sv;
ExtrusionRole role;
double height;
double flow_spacing;
double mm3_per_mm;
CODE:
RETVAL = new ExtrusionLoop ();
RETVAL->polygon.from_SV_check(polygon_sv);
RETVAL->role = role;
RETVAL->height = height;
RETVAL->flow_spacing = flow_spacing;
RETVAL->mm3_per_mm = mm3_per_mm;
OUTPUT:
RETVAL
@ -66,22 +64,12 @@ ExtrusionLoop::role(...)
RETVAL
double
ExtrusionLoop::height(...)
ExtrusionLoop::mm3_per_mm(...)
CODE:
if (items > 1) {
THIS->height = (double)SvNV(ST(1));
THIS->mm3_per_mm = (double)SvNV(ST(1));
}
RETVAL = THIS->height;
OUTPUT:
RETVAL
double
ExtrusionLoop::flow_spacing(...)
CODE:
if (items > 1) {
THIS->flow_spacing = (double)SvNV(ST(1));
}
RETVAL = THIS->flow_spacing;
RETVAL = THIS->mm3_per_mm;
OUTPUT:
RETVAL

View File

@ -33,18 +33,16 @@
%{
ExtrusionPath*
_new(CLASS, polyline_sv, role, height, flow_spacing)
_new(CLASS, polyline_sv, role, mm3_per_mm)
char* CLASS;
SV* polyline_sv;
ExtrusionRole role;
double height;
double flow_spacing;
double mm3_per_mm;
CODE:
RETVAL = new ExtrusionPath ();
RETVAL->polyline.from_SV_check(polyline_sv);
RETVAL->role = role;
RETVAL->height = height;
RETVAL->flow_spacing = flow_spacing;
RETVAL->mm3_per_mm = mm3_per_mm;
OUTPUT:
RETVAL
@ -71,22 +69,12 @@ ExtrusionPath::role(...)
RETVAL
double
ExtrusionPath::height(...)
ExtrusionPath::mm3_per_mm(...)
CODE:
if (items > 1) {
THIS->height = (double)SvNV(ST(1));
THIS->mm3_per_mm = (double)SvNV(ST(1));
}
RETVAL = THIS->height;
OUTPUT:
RETVAL
double
ExtrusionPath::flow_spacing(...)
CODE:
if (items > 1) {
THIS->flow_spacing = (double)SvNV(ST(1));
}
RETVAL = THIS->flow_spacing;
RETVAL = THIS->mm3_per_mm;
OUTPUT:
RETVAL