Satisfy test suite and CLI

xs-bb
Alessandro Ranellucci 2014-01-02 17:24:23 +01:00
parent e2f1040a76
commit 5bf0942f45
20 changed files with 300 additions and 272 deletions

View File

@ -15,18 +15,18 @@ our $Options = print_config_def();
{
no strict 'refs';
for my $opt_key (keys %$Options) {
*{$opt_key} = sub { $_[0]->_get($opt_key) };
*{$opt_key} = sub { $_[0]->get($opt_key) };
}
}
sub _get {
my ($self, $opt_key) = @_;
use XXX;
if (!defined first { $_ eq $opt_key } @{$self->get_keys}) {
ZZZ $opt_key;
}
return $self->get($opt_key);
}
# sub _get {
# my ($self, $opt_key) = @_;
# use XXX;
# if (!defined first { $_ eq $opt_key } @{$self->get_keys}) {
# ZZZ $opt_key;
# }
# return $self->get($opt_key);
# }
sub new_from_defaults {
my $class = shift;
@ -200,7 +200,8 @@ sub diff {
return [@diff];
}
# this method is idempotent by design
# this method is idempotent by design and only applies to ::DynamicConfig or ::Full
# objects because it performs cross checks
sub validate {
my $self = shift;
@ -317,6 +318,31 @@ sub validate {
if ($self->perimeter_acceleration || $self->infill_acceleration || $self->bridge_acceleration || $self->first_layer_acceleration)
&& !$self->default_acceleration;
# --spiral-vase
if ($self->spiral_vase) {
# Note that we might want to have more than one perimeter on the bottom
# solid layers.
die "Can't make more than one perimeter when spiral vase mode is enabled\n"
if $self->perimeters > 1;
die "Can't make less than one perimeter when spiral vase mode is enabled\n"
if $self->perimeters < 1;
die "Spiral vase mode is not compatible with non-zero fill density\n"
if $self->fill_density > 0;
die "Spiral vase mode is not compatible with top solid layers\n"
if $self->top_solid_layers > 0;
die "Spiral vase mode is not compatible with support material\n"
if $self->support_material || $self->support_material_enforce_layers > 0;
# This should be enforce automatically only on spiral layers and
# done on the others
die "Spiral vase mode is not compatible with retraction on layer change\n"
if defined first { $_ } @{ $self->retract_layer_change };
}
# general validation, quick and dirty
foreach my $opt_key (@{$self->get_keys}) {
my $opt = $Options->{$opt_key};

View File

@ -18,7 +18,7 @@ use constant OPTIONS => [qw(
has 'id' => (is => 'rw', required => 1);
has $_ => (is => 'ro', required => 1) for @{&OPTIONS};
has 'config'=> (is => 'ro', required => 1);
has 'use_relative_e_distances' => (is => 'ro', default => sub {0});
has 'E' => (is => 'rw', default => sub {0} );
has 'absolute_E' => (is => 'rw', default => sub {0} );
@ -56,7 +56,7 @@ sub scaled_wipe_distance {
sub extrude {
my ($self, $E) = @_;
$self->E(0) if $self->config->use_relative_e_distances;
$self->E(0) if $self->use_relative_e_distances;
$self->absolute_E($self->absolute_E + $E);
return $self->E($self->E + $E);
}

View File

@ -1,6 +1,7 @@
package Slic3r::Fill;
use Moo;
use Slic3r::ExtrusionPath ':roles';
use Slic3r::Fill::ArchimedeanChords;
use Slic3r::Fill::Base;
use Slic3r::Fill::Concentric;
@ -11,7 +12,7 @@ use Slic3r::Fill::Line;
use Slic3r::Fill::OctagramSpiral;
use Slic3r::Fill::PlanePath;
use Slic3r::Fill::Rectilinear;
use Slic3r::ExtrusionPath ':roles';
use Slic3r::Flow ':roles';
use Slic3r::Geometry qw(X Y PI scale chained_path);
use Slic3r::Geometry::Clipper qw(union union_ex diff diff_ex intersection_ex offset offset2);
use Slic3r::Surface ':types';
@ -50,7 +51,10 @@ sub make_fill {
my ($layerm) = @_;
Slic3r::debugf "Filling layer %d:\n", $layerm->id;
my $fill_density = $layerm->config->fill_density;
my $fill_density = $layerm->config->fill_density;
my $infill_flow = $layerm->flow(FLOW_ROLE_INFILL);
my $solid_infill_flow = $layerm->flow(FLOW_ROLE_SOLID_INFILL);
my @surfaces = ();
@ -95,7 +99,7 @@ sub make_fill {
# 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 = $layerm->solid_infill_flow->scaled_spacing * &Slic3r::INFILL_OVERLAP_OVER_SPACING;
my $distance_between_surfaces = $infill_flow->scaled_spacing * &Slic3r::INFILL_OVERLAP_OVER_SPACING;
{
my $collapsed = diff(
[ map @{$_->expolygon}, @surfaces ],
@ -133,11 +137,10 @@ sub make_fill {
my $filler = $layerm->config->fill_pattern;
my $density = $fill_density;
my $flow = ($surface->surface_type == S_TYPE_TOP)
? $layerm->top_infill_flow
? $layerm->flow(FLOW_ROLE_TOP_SOLID_INFILL)
: $surface->is_solid
? $layerm->solid_infill_flow
: $layerm->infill_flow;
my $flow_spacing = $flow->spacing;
? $solid_infill_flow
: $infill_flow;
my $is_bridge = $layerm->id > 0 && $surface->is_bridge;
my $is_solid = $surface->is_solid;
@ -147,7 +150,7 @@ sub make_fill {
$filler = $layerm->config->solid_fill_pattern;
if ($is_bridge) {
$filler = 'rectilinear';
$flow_spacing = $layerm->extruders->{infill}->bridge_flow->spacing;
$flow = $layerm->flow(FLOW_ROLE_SOLID_INFILL, 1);
} elsif ($surface->surface_type == S_TYPE_INTERNALSOLID) {
$filler = 'rectilinear';
}
@ -155,6 +158,8 @@ 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);
@ -166,7 +171,7 @@ sub make_fill {
next unless @polylines;
# ugly hack(tm) to get the right amount of flow (GCode.pm should be fixed)
$params->{flow_spacing} = $layerm->extruders->{infill}->bridge_flow->width if $is_bridge;
$params->{flow_spacing} = $flow->width if $is_bridge;
# save into layer
push @fills, my $collection = Slic3r::ExtrusionPath::Collection->new;

View File

@ -36,7 +36,10 @@ sub BUILDARGS {
$args{width} = $args{layer_height} * $1 / 100;
}
$args{spacing} = $self->_spacing(@args{qw(width nozzle_diameter layer_height bridge_flow_ratio)});
%args = @args{qw(width spacing)};
%args = (
width => $args{width},
spacing => $args{spacing},
);
}
return {%args};

View File

@ -3,11 +3,12 @@ use Moo;
use List::Util qw(min first);
use Slic3r::ExtrusionPath ':roles';
use Slic3r::Flow ':roles';
use Slic3r::Geometry qw(epsilon scale unscale scaled_epsilon points_coincide PI X Y B);
use Slic3r::Geometry::Clipper qw(union_ex);
use Slic3r::Surface ':types';
has 'config' => (is => 'ro', required => 1);
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');
@ -16,6 +17,7 @@ has 'enable_loop_clipping' => (is => 'rw', default => sub {1});
has 'enable_wipe' => (is => 'lazy'); # at least one extruder has wipe enabled
has 'layer_count' => (is => 'ro', required => 1 );
has 'layer' => (is => 'rw');
has 'region' => (is => 'rw');
has '_layer_islands' => (is => 'rw');
has '_upper_layer_islands' => (is => 'rw');
has '_layer_overhangs' => (is => 'ro', default => sub { Slic3r::ExPolygon::Collection->new });
@ -23,6 +25,8 @@ has 'shift_x' => (is => 'rw', default => sub {0} );
has 'shift_y' => (is => 'rw', default => sub {0} );
has 'z' => (is => 'rw');
has 'speed' => (is => 'rw');
has '_extrusion_axis' => (is => 'rw');
has '_retract_lift' => (is => 'rw');
has 'speeds' => (is => 'lazy'); # mm/min
has 'external_mp' => (is => 'rw');
@ -38,12 +42,19 @@ has 'last_f' => (is => 'rw', default => sub {""});
has 'last_fan_speed' => (is => 'rw', default => sub {0});
has 'wipe_path' => (is => 'rw');
sub BUILD {
my ($self) = @_;
$self->_extrusion_axis($self->print_config->get_extrusion_axis);
$self->_retract_lift($self->print_config->retract_lift->[0]);
}
sub _build_speeds {
my $self = shift;
return {
map { $_ => 60 * $self->config->get_value("${_}_speed") }
map { $_ => 60 * $self->print_config->get_value("${_}_speed") }
qw(travel perimeter small_perimeter external_perimeter infill
solid_infill top_solid_infill support_material bridge gap_fill retract),
solid_infill top_solid_infill bridge gap_fill retract),
};
}
@ -59,7 +70,6 @@ my %role_speeds = (
&EXTR_ROLE_BRIDGE => 'bridge',
&EXTR_ROLE_INTERNALBRIDGE => 'solid_infill',
&EXTR_ROLE_SKIRT => 'perimeter',
&EXTR_ROLE_SUPPORTMATERIAL => 'support_material',
&EXTR_ROLE_GAPFILL => 'gap_fill',
);
@ -97,29 +107,29 @@ sub change_layer {
$self->_layer_islands($layer->islands);
$self->_upper_layer_islands($layer->upper_layer ? $layer->upper_layer->islands : []);
$self->_layer_overhangs->clear;
if ($layer->id > 0 && ($layer->config->overhangs || $self->config->start_perimeters_at_non_overhang)) {
if ($layer->id > 0 && ($self->print_config->overhangs || $self->print_config->start_perimeters_at_non_overhang)) {
$self->_layer_overhangs->append(
# clone ExPolygons because they come from Surface objects but will be used outside here
map $_->expolygon, map @{$_->slices->filter_by_type(S_TYPE_BOTTOM)}, @{$layer->regions}
);
}
if ($self->config->avoid_crossing_perimeters) {
if ($self->print_config->avoid_crossing_perimeters) {
$self->layer_mp(Slic3r::GCode::MotionPlanner->new(
islands => union_ex([ map @$_, @{$layer->slices} ], 1),
));
}
my $gcode = "";
if ($self->config->gcode_flavor =~ /^(?:makerware|sailfish)$/) {
if ($self->print_config->gcode_flavor =~ /^(?:makerware|sailfish)$/) {
$gcode .= sprintf "M73 P%s%s\n",
int(99 * ($layer->id / ($self->layer_count - 1))),
($self->config->gcode_comments ? ' ; update progress' : '');
($self->print_config->gcode_comments ? ' ; update progress' : '');
}
if ($self->config->first_layer_acceleration) {
if ($self->print_config->first_layer_acceleration) {
if ($layer->id == 0) {
$gcode .= $self->set_acceleration($self->config->first_layer_acceleration);
$gcode .= $self->set_acceleration($self->print_config->first_layer_acceleration);
} elsif ($layer->id == 1) {
$gcode .= $self->set_acceleration($self->config->default_acceleration);
$gcode .= $self->set_acceleration($self->print_config->default_acceleration);
}
}
@ -133,7 +143,7 @@ sub move_z {
my $gcode = "";
$z += $self->config->z_offset;
$z += $self->print_config->z_offset;
my $current_z = $self->z;
my $nominal_z = defined $current_z ? ($current_z - $self->lifted) : undef;
@ -181,11 +191,11 @@ sub extrude_loop {
# find candidate starting points
# start looking for concave vertices not being overhangs
my @concave = ();
if ($self->config->start_perimeters_at_concave_points) {
if ($self->print_config->start_perimeters_at_concave_points) {
@concave = $polygon->concave_points;
}
my @candidates = ();
if ($self->config->start_perimeters_at_non_overhang) {
if ($self->print_config->start_perimeters_at_non_overhang) {
@candidates = grep !$self->_layer_overhangs->contains_point($_), @concave;
}
if (!@candidates) {
@ -193,7 +203,7 @@ sub extrude_loop {
@candidates = @concave;
if (!@candidates) {
# if none, look for any non-overhang vertex
if ($self->config->start_perimeters_at_non_overhang) {
if ($self->print_config->start_perimeters_at_non_overhang) {
@candidates = grep !$self->_layer_overhangs->contains_point($_), @$polygon;
}
if (!@candidates) {
@ -206,9 +216,9 @@ sub extrude_loop {
# find the point of the loop that is closest to the current extruder position
# or randomize if requested
my $last_pos = $self->last_pos;
if ($self->config->randomize_start && $loop->role == EXTR_ROLE_CONTOUR_INTERNAL_PERIMETER) {
$last_pos = Slic3r::Point->new(scale $self->config->print_center->[X], scale $self->config->bed_size->[Y]);
$last_pos->rotate(rand(2*PI), $self->config->print_center);
if ($self->print_config->randomize_start && $loop->role == EXTR_ROLE_CONTOUR_INTERNAL_PERIMETER) {
$last_pos = Slic3r::Point->new(scale $self->print_config->print_center->[X], scale $self->print_config->bed_size->[Y]);
$last_pos->rotate(rand(2*PI), $self->print_config->print_center);
}
# split the loop at the starting point and make a path
@ -224,7 +234,7 @@ sub extrude_loop {
my @paths = ();
# detect overhanging/bridging perimeters
if ($self->layer->config->overhangs && $extrusion_path->is_perimeter && $self->_layer_overhangs->count > 0) {
if ($self->layer->print->config->overhangs && $extrusion_path->is_perimeter && $self->_layer_overhangs->count > 0) {
# get non-overhang paths by subtracting overhangs from the loop
push @paths,
map $_->clone,
@ -234,7 +244,7 @@ sub extrude_loop {
push @paths,
map {
$_->role(EXTR_ROLE_OVERHANG_PERIMETER);
$_->flow_spacing($self->extruder->bridge_flow->width);
$_->flow_spacing($self->region->flow(FLOW_ROLE_PERIMETER, undef, 1)->width);
$_
}
map $_->clone,
@ -259,7 +269,7 @@ sub extrude_loop {
$self->wipe_path($extrusion_path->polyline->clone) if $self->enable_wipe;
# make a little move inwards before leaving loop
if ($loop->role == EXTR_ROLE_EXTERNAL_PERIMETER && defined $self->layer && $self->layer->object->config->perimeters > 1) {
if ($loop->role == EXTR_ROLE_EXTERNAL_PERIMETER && defined $self->layer && $self->region->config->perimeters > 1) {
# detect angle between last and first segment
# the side depends on the original winding order of the polygon (left for contours, right for holes)
my @points = $was_clockwise ? (-2, 1) : (1, -2);
@ -299,13 +309,13 @@ sub extrude_path {
# adjust acceleration
my $acceleration;
if (!$self->config->first_layer_acceleration || $self->layer->id != 0) {
if ($self->config->perimeter_acceleration && $path->is_perimeter) {
$acceleration = $self->config->perimeter_acceleration;
} elsif ($self->config->infill_acceleration && $path->is_fill) {
$acceleration = $self->config->infill_acceleration;
} elsif ($self->config->infill_acceleration && $path->is_bridge) {
$acceleration = $self->config->bridge_acceleration;
if (!$self->print_config->first_layer_acceleration || $self->layer->id != 0) {
if ($self->print_config->perimeter_acceleration && $path->is_perimeter) {
$acceleration = $self->print_config->perimeter_acceleration;
} elsif ($self->print_config->infill_acceleration && $path->is_fill) {
$acceleration = $self->print_config->infill_acceleration;
} elsif ($self->print_config->infill_acceleration && $path->is_bridge) {
$acceleration = $self->print_config->bridge_acceleration;
}
$gcode .= $self->set_acceleration($acceleration) if $acceleration;
}
@ -322,15 +332,13 @@ sub extrude_path {
# calculate extrusion length per distance unit
my $e = $self->extruder->e_per_mm3 * $area;
$e = 0 if !$self->config->extrusion_axis;
$e = 0 if !$self->_extrusion_axis;
# set speed
$self->speed( $params{speed} || $role_speeds{$path->role} || die "Unknown role: " . $path->role );
my $F = $self->speeds->{$self->speed} // $self->speed;
if ($self->layer->id == 0) {
$F = $self->config->first_layer_speed =~ /^(\d+(?:\.\d+)?)%$/
? sprintf("%.3f", $F * $1/100)
: $self->config->first_layer_speed * 60;
$F = $self->print_config->get_abs_value_over('first_layer_speed', $F/60) * 60;
}
# extrude arc or line
@ -350,12 +358,12 @@ sub extrude_path {
$gcode .= sprintf "G1 X%.3f Y%.3f",
($point->x * &Slic3r::SCALING_FACTOR) + $self->shift_x - $self->extruder->extruder_offset->[X],
($point->y * &Slic3r::SCALING_FACTOR) + $self->shift_y - $self->extruder->extruder_offset->[Y]; #**
$gcode .= sprintf(" %s%.5f", $self->config->extrusion_axis, $E)
$gcode .= sprintf(" %s%.5f", $self->_extrusion_axis, $E)
if $E;
$gcode .= " F$local_F"
if $local_F;
$gcode .= " ; $description"
if $self->config->gcode_comments;
if $self->print_config->gcode_comments;
$gcode .= "\n";
# only include F in the first line
@ -369,19 +377,14 @@ sub extrude_path {
$gcode .= ";_BRIDGE_FAN_END\n" if $path->is_bridge;
$self->last_pos($path->last_point);
if ($self->config->cooling) {
if ($self->print_config->cooling) {
my $path_time = $path_length / $F * 60;
if ($self->layer->id == 0) {
$path_time = $self->config->first_layer_speed =~ /^(\d+(?:\.\d+)?)%$/
? $path_time / ($1/100)
: $path_length / $self->config->first_layer_speed * 60;
}
$self->elapsed_time($self->elapsed_time + $path_time);
}
# reset acceleration
$gcode .= $self->set_acceleration($self->config->default_acceleration)
if $acceleration && $self->config->default_acceleration;
$gcode .= $self->set_acceleration($self->print_config->default_acceleration)
if $acceleration && $self->print_config->default_acceleration;
return $gcode;
}
@ -400,7 +403,7 @@ sub travel_to {
# skip retraction if the travel move is contained in an island in the current layer
# *and* in an island in the upper layer (so that the ooze will not be visible)
if ($travel->length < scale $self->extruder->retract_before_travel
|| ($self->config->only_retract_when_crossing_perimeters
|| ($self->print_config->only_retract_when_crossing_perimeters
&& (first { $_->contains_line($travel) } @{$self->_upper_layer_islands})
&& (first { $_->contains_line($travel) } @{$self->_layer_islands}))
|| (defined $role && $role == EXTR_ROLE_SUPPORTMATERIAL && (first { $_->contains_line($travel) } @{$self->layer->support_islands}))
@ -408,7 +411,7 @@ sub travel_to {
$self->straight_once(0);
$self->speed('travel');
$gcode .= $self->G0($point, undef, 0, $comment || "");
} elsif (!$self->config->avoid_crossing_perimeters || $self->straight_once) {
} elsif (!$self->print_config->avoid_crossing_perimeters || $self->straight_once) {
$self->straight_once(0);
$gcode .= $self->retract;
$self->speed('travel');
@ -441,7 +444,7 @@ sub _plan {
my @travel = @{$mp->shortest_path($self->last_pos, $point)->lines};
# if the path is not contained in a single island we need to retract
my $need_retract = !$self->config->only_retract_when_crossing_perimeters;
my $need_retract = !$self->print_config->only_retract_when_crossing_perimeters;
if (!$need_retract) {
$need_retract = 1;
foreach my $island (@{$self->_upper_layer_islands}) {
@ -481,14 +484,14 @@ sub retract {
if ($self->extruder->wipe && $self->wipe_path) {
my @points = @{$self->wipe_path};
$wipe_path = Slic3r::Polyline->new($self->last_pos, @{$self->wipe_path}[1..$#{$self->wipe_path}]);
$wipe_path->clip_end($wipe_path->length - $self->extruder->scaled_wipe_distance($self->config->travel_speed));
$wipe_path->clip_end($wipe_path->length - $self->extruder->scaled_wipe_distance($self->print_config->travel_speed));
}
# prepare moves
my $retract = [undef, undef, -$length, $comment];
my $lift = ($self->extruder->retract_lift == 0 || defined $params{move_z}) && !$self->lifted
my $lift = ($self->_retract_lift == 0 || defined $params{move_z}) && !$self->lifted
? undef
: [undef, $self->z + $self->extruder->retract_lift, 0, 'lift plate during travel'];
: [undef, $self->z + $self->_retract_lift, 0, 'lift plate during travel'];
# check that we have a positive wipe length
if ($wipe_path) {
@ -500,7 +503,7 @@ sub retract {
my $segment_length = $line->length;
# reduce retraction length a bit to avoid effective retraction speed to be greater than the configured one
# due to rounding
my $e = $retract->[2] * ($segment_length / $self->extruder->scaled_wipe_distance($self->config->travel_speed)) * 0.95;
my $e = $retract->[2] * ($segment_length / $self->extruder->scaled_wipe_distance($self->print_config->travel_speed)) * 0.95;
$retracted += $e;
$gcode .= $self->G1($line->b, undef, $e, $retract->[3] . ";_WIPE");
}
@ -510,7 +513,7 @@ sub retract {
$self->speed('retract');
$gcode .= $self->G1(undef, undef, $retract->[2] - $retracted, $comment);
}
} elsif ($self->config->use_firmware_retraction) {
} elsif ($self->print_config->use_firmware_retraction) {
$gcode .= "G10 ; retract\n";
} else {
$self->speed('retract');
@ -518,23 +521,23 @@ sub retract {
}
if (!$self->lifted) {
$self->speed('travel');
if (defined $params{move_z} && $self->extruder->retract_lift > 0) {
my $travel = [undef, $params{move_z} + $self->extruder->retract_lift, 0, 'move to next layer (' . $self->layer->id . ') and lift'];
if (defined $params{move_z} && $self->_retract_lift > 0) {
my $travel = [undef, $params{move_z} + $self->_retract_lift, 0, 'move to next layer (' . $self->layer->id . ') and lift'];
$gcode .= $self->G0(@$travel);
$self->lifted($self->extruder->retract_lift);
$self->lifted($self->_retract_lift);
} elsif ($lift) {
$gcode .= $self->G1(@$lift);
}
}
$self->extruder->retracted($self->extruder->retracted + $length);
$self->extruder->restart_extra($restart_extra);
$self->lifted($self->extruder->retract_lift) if $lift;
$self->lifted($self->_retract_lift) if $lift;
# reset extrusion distance during retracts
# this makes sure we leave sufficient precision in the firmware
$gcode .= $self->reset_e;
$gcode .= "M103 ; extruder off\n" if $self->config->gcode_flavor eq 'makerware';
$gcode .= "M103 ; extruder off\n" if $self->print_config->gcode_flavor eq 'makerware';
return $gcode;
}
@ -543,7 +546,7 @@ sub unretract {
my ($self) = @_;
my $gcode = "";
$gcode .= "M101 ; extruder on\n" if $self->config->gcode_flavor eq 'makerware';
$gcode .= "M101 ; extruder on\n" if $self->print_config->gcode_flavor eq 'makerware';
if ($self->lifted) {
$self->speed('travel');
@ -554,15 +557,15 @@ sub unretract {
my $to_unretract = $self->extruder->retracted + $self->extruder->restart_extra;
if ($to_unretract) {
$self->speed('retract');
if ($self->config->use_firmware_retraction) {
if ($self->print_config->use_firmware_retraction) {
$gcode .= "G11 ; unretract\n";
} elsif ($self->config->extrusion_axis) {
} elsif ($self->_extrusion_axis) {
# use G1 instead of G0 because G0 will blend the restart with the previous travel move
$gcode .= sprintf "G1 %s%.5f F%.3f",
$self->config->extrusion_axis,
$self->_extrusion_axis,
$self->extruder->extrude($to_unretract),
$self->extruder->retract_speed_mm_min;
$gcode .= " ; compensate retraction" if $self->config->gcode_comments;
$gcode .= " ; compensate retraction" if $self->print_config->gcode_comments;
$gcode .= "\n";
}
$self->extruder->retracted(0);
@ -574,11 +577,11 @@ sub unretract {
sub reset_e {
my ($self) = @_;
return "" if $self->config->gcode_flavor =~ /^(?:mach3|makerware|sailfish)$/;
return "" if $self->print_config->gcode_flavor =~ /^(?:mach3|makerware|sailfish)$/;
$self->extruder->E(0) if $self->extruder;
return sprintf "G92 %s0%s\n", $self->config->extrusion_axis, ($self->config->gcode_comments ? ' ; reset extrusion distance' : '')
if $self->config->extrusion_axis && !$self->config->use_relative_e_distances;
return sprintf "G92 %s0%s\n", $self->_extrusion_axis, ($self->print_config->gcode_comments ? ' ; reset extrusion distance' : '')
if $self->_extrusion_axis && !$self->print_config->use_relative_e_distances;
}
sub set_acceleration {
@ -586,12 +589,12 @@ sub set_acceleration {
return "" if !$acceleration;
return sprintf "M204 S%s%s\n",
$acceleration, ($self->config->gcode_comments ? ' ; adjust acceleration' : '');
$acceleration, ($self->print_config->gcode_comments ? ' ; adjust acceleration' : '');
}
sub G0 {
my $self = shift;
return $self->G1(@_) if !($self->config->g0 || $self->config->gcode_flavor eq 'mach3');
return $self->G1(@_) if !($self->print_config->g0 || $self->print_config->gcode_flavor eq 'mach3');
return $self->_G0_G1("G0", @_);
}
@ -628,11 +631,11 @@ sub _Gx {
$gcode .= sprintf " F%.3f", $F;
# output extrusion distance
if ($e && $self->config->extrusion_axis) {
$gcode .= sprintf " %s%.5f", $self->config->extrusion_axis, $self->extruder->extrude($e);
if ($e && $self->_extrusion_axis) {
$gcode .= sprintf " %s%.5f", $self->_extrusion_axis, $self->extruder->extrude($e);
}
$gcode .= " ; $comment" if $comment && $self->config->gcode_comments;
$gcode .= " ; $comment" if $comment && $self->print_config->gcode_comments;
return "$gcode\n";
}
@ -653,8 +656,8 @@ sub set_extruder {
$gcode .= $self->retract(toolchange => 1) if defined $self->extruder;
# append custom toolchange G-code
if (defined $self->extruder && $self->config->toolchange_gcode) {
$gcode .= sprintf "%s\n", $self->replace_variables($self->config->toolchange_gcode, {
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,
});
@ -669,24 +672,24 @@ sub set_extruder {
? $self->extruder->first_layer_temperature
: $self->extruder->temperature;
# we assume that heating is always slower than cooling, so no need to block
$gcode .= $self->set_temperature($temp + $self->config->standby_temperature_delta, 0);
$gcode .= $self->set_temperature($temp + $self->print_config->standby_temperature_delta, 0);
}
# set the new extruder
$self->extruder($extruder);
$gcode .= sprintf "%s%d%s\n",
($self->config->gcode_flavor eq 'makerware'
($self->print_config->gcode_flavor eq 'makerware'
? 'M135 T'
: $self->config->gcode_flavor eq 'sailfish'
: $self->print_config->gcode_flavor eq 'sailfish'
? 'M108 T'
: 'T'),
$extruder->id,
($self->config->gcode_comments ? ' ; change extruder' : '');
($self->print_config->gcode_comments ? ' ; change extruder' : '');
$gcode .= $self->reset_e;
# set the new extruder to the operating temperature
if ($self->config->ooze_prevention) {
if ($self->print_config->ooze_prevention) {
my $temp = defined $self->layer && $self->layer->id == 0
? $self->extruder->first_layer_temperature
: $self->extruder->temperature;
@ -702,18 +705,18 @@ sub set_fan {
if ($self->last_fan_speed != $speed || $dont_save) {
$self->last_fan_speed($speed) if !$dont_save;
if ($speed == 0) {
my $code = $self->config->gcode_flavor eq 'teacup'
my $code = $self->print_config->gcode_flavor eq 'teacup'
? 'M106 S0'
: $self->config->gcode_flavor =~ /^(?:makerware|sailfish)$/
: $self->print_config->gcode_flavor =~ /^(?:makerware|sailfish)$/
? 'M127'
: 'M107';
return sprintf "$code%s\n", ($self->config->gcode_comments ? ' ; disable fan' : '');
return sprintf "$code%s\n", ($self->print_config->gcode_comments ? ' ; disable fan' : '');
} else {
if ($self->config->gcode_flavor =~ /^(?:makerware|sailfish)$/) {
return sprintf "M126%s\n", ($self->config->gcode_comments ? ' ; enable fan' : '');
if ($self->print_config->gcode_flavor =~ /^(?:makerware|sailfish)$/) {
return sprintf "M126%s\n", ($self->print_config->gcode_comments ? ' ; enable fan' : '');
} else {
return sprintf "M106 %s%d%s\n", ($self->config->gcode_flavor eq 'mach3' ? 'P' : 'S'),
(255 * $speed / 100), ($self->config->gcode_comments ? ' ; enable fan' : '');
return sprintf "M106 %s%d%s\n", ($self->print_config->gcode_flavor eq 'mach3' ? 'P' : 'S'),
(255 * $speed / 100), ($self->print_config->gcode_comments ? ' ; enable fan' : '');
}
}
}
@ -723,17 +726,17 @@ sub set_fan {
sub set_temperature {
my ($self, $temperature, $wait, $tool) = @_;
return "" if $wait && $self->config->gcode_flavor =~ /^(?:makerware|sailfish)$/;
return "" if $wait && $self->print_config->gcode_flavor =~ /^(?:makerware|sailfish)$/;
my ($code, $comment) = ($wait && $self->config->gcode_flavor ne 'teacup')
my ($code, $comment) = ($wait && $self->print_config->gcode_flavor ne 'teacup')
? ('M109', 'wait for temperature to be reached')
: ('M104', 'set temperature');
my $gcode = sprintf "$code %s%d %s; $comment\n",
($self->config->gcode_flavor eq 'mach3' ? 'P' : 'S'), $temperature,
(defined $tool && ($self->multiple_extruders || $self->config->gcode_flavor =~ /^(?:makerware|sailfish)$/)) ? "T$tool " : "";
($self->print_config->gcode_flavor eq 'mach3' ? 'P' : 'S'), $temperature,
(defined $tool && ($self->multiple_extruders || $self->print_config->gcode_flavor =~ /^(?:makerware|sailfish)$/)) ? "T$tool " : "";
$gcode .= "M116 ; wait for temperature to be reached\n"
if $self->config->gcode_flavor eq 'teacup' && $wait;
if $self->print_config->gcode_flavor eq 'teacup' && $wait;
return $gcode;
}
@ -741,21 +744,21 @@ sub set_temperature {
sub set_bed_temperature {
my ($self, $temperature, $wait) = @_;
my ($code, $comment) = ($wait && $self->config->gcode_flavor ne 'teacup')
? (($self->config->gcode_flavor =~ /^(?:makerware|sailfish)$/ ? 'M109' : 'M190'), 'wait for bed temperature to be reached')
my ($code, $comment) = ($wait && $self->print_config->gcode_flavor ne 'teacup')
? (($self->print_config->gcode_flavor =~ /^(?:makerware|sailfish)$/ ? 'M109' : 'M190'), 'wait for bed temperature to be reached')
: ('M140', 'set bed temperature');
my $gcode = sprintf "$code %s%d ; $comment\n",
($self->config->gcode_flavor eq 'mach3' ? 'P' : 'S'), $temperature;
($self->print_config->gcode_flavor eq 'mach3' ? 'P' : 'S'), $temperature;
$gcode .= "M116 ; wait for bed temperature to be reached\n"
if $self->config->gcode_flavor eq 'teacup' && $wait;
if $self->print_config->gcode_flavor eq 'teacup' && $wait;
return $gcode;
}
sub replace_variables {
my ($self, $string, $extra) = @_;
return $self->config->replace_options($string, { %{$self->extra_variables}, %{ $extra || {} } });
return $self->print_config->replace_options($string, { %{$self->extra_variables}, %{ $extra || {} } });
}
1;

View File

@ -104,7 +104,7 @@ sub flush_path {
$gcode .= sprintf " I%.3f J%.3f", map { unscale($arc_center->[$_] - $cur_path->[0][$_]) } (X,Y);
my $E = 0; # TODO: compute E using $length
$gcode .= sprintf(" %s%.5f", $self->config->extrusion_axis, $E)
$gcode .= sprintf(" %s%.5f", $self->config->get_extrusion_axis, $E)
if $E;
my $F = 0; # TODO: extract F from original moves

View File

@ -1,7 +1,7 @@
package Slic3r::GCode::CoolingBuffer;
use Moo;
has 'config' => (is => 'ro', required => 1);
has 'config' => (is => 'ro', required => 1); # Slic3r::Config::Print
has 'gcodegen' => (is => 'ro', required => 1);
has 'gcode' => (is => 'rw', default => sub {""});
has 'elapsed_time' => (is => 'rw', default => sub {0});

View File

@ -19,24 +19,24 @@ has '_last_obj_copy' => (is => 'rw');
sub _build_spiralvase {
my $self = shift;
return $self->gcodegen->config->spiral_vase
? Slic3r::GCode::SpiralVase->new(config => $self->gcodegen->config)
return $self->print->config->spiral_vase
? Slic3r::GCode::SpiralVase->new(config => $self->print->config)
: undef;
}
sub _build_vibration_limit {
my $self = shift;
return $self->gcodegen->config->vibration_limit
? Slic3r::GCode::VibrationLimit->new(config => $self->gcodegen->config)
return $self->print->config->vibration_limit
? Slic3r::GCode::VibrationLimit->new(config => $self->print->config)
: undef;
}
sub _build_arc_fitting {
my $self = shift;
return $self->gcodegen->config->gcode_arcs
? Slic3r::GCode::ArcFitting->new(config => $self->gcodegen->config)
return $self->print->config->gcode_arcs
? Slic3r::GCode::ArcFitting->new(config => $self->print->config)
: undef;
}
@ -45,44 +45,46 @@ sub process_layer {
my ($layer, $object_copies) = @_;
my $gcode = "";
my $object = $layer->object;
# check whether we're going to apply spiralvase logic
my $spiralvase = defined $self->spiralvase
&& ($layer->id > 0 || $self->gcodegen->config->brim_width == 0)
&& ($layer->id >= $self->gcodegen->config->skirt_height && $self->gcodegen->config->skirt_height != -1)
&& ($layer->id >= $self->gcodegen->config->bottom_solid_layers);
&& ($layer->id > 0 || $self->print->config->brim_width == 0)
&& ($layer->id >= $self->print->config->skirt_height && $self->print->config->skirt_height != -1)
&& !defined(first { $_->config->bottom_solid_layers > $layer->id } @{$layer->regions});
# if we're going to apply spiralvase to this layer, disable loop clipping
$self->gcodegen->enable_loop_clipping(!$spiralvase);
if (!$self->second_layer_things_done && $layer->id == 1) {
for my $t (grep $self->extruders->[$_], 0 .. $#{$self->gcodegen->config->temperature}) {
for my $t (grep $self->extruders->[$_], 0 .. $#{$self->print->config->temperature}) {
$gcode .= $self->gcodegen->set_temperature($self->extruders->[$t]->temperature, 0, $t)
if $self->print->extruders->[$t]->temperature && $self->extruders->[$t]->temperature != $self->extruders->[$t]->first_layer_temperature;
}
$gcode .= $self->gcodegen->set_bed_temperature($self->gcodegen->config->bed_temperature)
if $self->gcodegen->config->bed_temperature && $self->gcodegen->config->bed_temperature != $self->gcodegen->config->first_layer_bed_temperature;
$gcode .= $self->gcodegen->set_bed_temperature($self->print->config->bed_temperature)
if $self->print->config->bed_temperature && $self->print->config->bed_temperature != $self->print->config->first_layer_bed_temperature;
$self->second_layer_things_done(1);
}
# set new layer - this will change Z and force a retraction if retract_layer_change is enabled
$gcode .= $self->gcodegen->change_layer($layer);
$gcode .= $self->gcodegen->replace_variables($self->gcodegen->config->layer_gcode, {
$gcode .= $self->gcodegen->replace_variables($self->print->config->layer_gcode, {
layer_num => $self->gcodegen->layer->id,
}) . "\n" if $self->gcodegen->config->layer_gcode;
}) . "\n" if $self->print->config->layer_gcode;
# extrude skirt
if (((values %{$self->skirt_done}) < $self->gcodegen->config->skirt_height || $self->gcodegen->config->skirt_height == -1)
if (((values %{$self->skirt_done}) < $self->print->config->skirt_height || $self->print->config->skirt_height == -1)
&& !$self->skirt_done->{$layer->print_z}) {
$self->gcodegen->set_shift(@{$self->shift});
$gcode .= $self->gcodegen->set_extruder($self->extruders->[0]);
# skip skirt if we have a large brim
if ($layer->id < $self->gcodegen->config->skirt_height || $self->gcodegen->config->skirt_height == -1) {
if ($layer->id < $self->print->config->skirt_height || $self->print->config->skirt_height == -1) {
# distribute skirt loops across all extruders
my @skirt_loops = @{$self->print->skirt};
for my $i (0 .. $#skirt_loops) {
# 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->gcodegen->config->skirts);
last if ($layer->id > 0) && ($i >= $self->print->config->skirts);
$gcode .= $self->gcodegen->set_extruder($self->extruders->[ ($i/@{$self->extruders}) % @{$self->extruders} ])
if $layer->id == 0;
$gcode .= $self->gcodegen->extrude_loop($skirt_loops[$i], 'skirt');
@ -94,7 +96,7 @@ sub process_layer {
# extrude brim
if (!$self->brim_done) {
$gcode .= $self->gcodegen->set_extruder($self->extruders->[$self->gcodegen->config->support_material_extruder-1]);
$gcode .= $self->gcodegen->set_extruder($self->extruders->[$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);
@ -109,15 +111,17 @@ sub process_layer {
# extrude support material before other things because it might use a lower Z
# and also because we avoid travelling on other things when printing it
if ($self->print->has_support_material && $layer->isa('Slic3r::Layer::Support')) {
if ($layer->isa('Slic3r::Layer::Support')) {
if ($layer->support_interface_fills->count > 0) {
$gcode .= $self->gcodegen->set_extruder($self->extruders->[$self->gcodegen->config->support_material_interface_extruder-1]);
$gcode .= $self->gcodegen->extrude_path($_, 'support material interface')
$gcode .= $self->gcodegen->set_extruder($self->extruders->[$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->[$self->gcodegen->config->support_material_extruder-1]);
$gcode .= $self->gcodegen->extrude_path($_, 'support material')
$gcode .= $self->gcodegen->set_extruder($self->extruders->[$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)};
}
}
@ -126,16 +130,17 @@ sub process_layer {
my @region_ids = 0 .. ($self->print->regions_count-1);
if ($self->gcodegen->multiple_extruders) {
my $last_extruder = $self->gcodegen->extruder;
my $best_region_id = first { $self->print->regions->[$_]->extruders->{perimeter} eq $last_extruder } @region_ids;
my $best_region_id = first { $self->print->regions->[$_]->config->perimeter_extruder-1 eq $last_extruder } @region_ids;
@region_ids = ($best_region_id, grep $_ != $best_region_id, @region_ids) if $best_region_id;
}
foreach my $region_id (@region_ids) {
my $layerm = $layer->regions->[$region_id] or next;
my $region = $self->print->regions->[$region_id];
$self->gcodegen->region($region);
my @islands = ();
if ($self->gcodegen->config->avoid_crossing_perimeters) {
if ($self->print->config->avoid_crossing_perimeters) {
push @islands, { perimeters => [], fills => [] }
for 1 .. (@{$layer->slices} || 1); # make sure we have at least one island hash to avoid failure of the -1 subscript below
PERIMETER: foreach my $perimeter (@{$layerm->perimeters}) {
@ -166,8 +171,8 @@ sub process_layer {
foreach my $island (@islands) {
# give priority to infill if we were already using its extruder and it wouldn't
# be good for perimeters
if ($self->gcodegen->config->infill_first
|| ($self->gcodegen->multiple_extruders && $region->extruders->{infill} eq $self->gcodegen->extruder) && $region->extruders->{infill} ne $region->extruders->{perimeter}) {
if ($self->print->config->infill_first
|| ($self->gcodegen->multiple_extruders && $region->config->infill_extruder-1 == $self->gcodegen->extruder->id && $region->config->infill_extruder != $region->config->perimeter_extruder)) {
$gcode .= $self->_extrude_infill($island, $region);
$gcode .= $self->_extrude_perimeters($island, $region);
} else {
@ -184,11 +189,11 @@ sub process_layer {
# apply vibration limit if enabled
$gcode = $self->vibration_limit->process($gcode)
if $self->gcodegen->config->vibration_limit != 0;
if $self->print->config->vibration_limit != 0;
# apply arc fitting if enabled
$gcode = $self->arc_fitting->process($gcode)
if $self->gcodegen->config->gcode_arcs;
if $self->print->config->gcode_arcs;
return $gcode;
}
@ -200,7 +205,7 @@ sub _extrude_perimeters {
return "" if !@{ $island->{perimeters} };
my $gcode = "";
$gcode .= $self->gcodegen->set_extruder($region->extruders->{perimeter});
$gcode .= $self->gcodegen->set_extruder($self->extruders->[$region->config->perimeter_extruder-1]);
$gcode .= $self->gcodegen->extrude($_, 'perimeter') for @{ $island->{perimeters} };
return $gcode;
}
@ -212,7 +217,7 @@ sub _extrude_infill {
return "" if !@{ $island->{fills} };
my $gcode = "";
$gcode .= $self->gcodegen->set_extruder($region->extruders->{infill});
$gcode .= $self->gcodegen->set_extruder($self->extruders->[$region->config->infill_extruder-1]);
for my $fill (@{ $island->{fills} }) {
if ($fill->isa('Slic3r::ExtrusionPath::Collection')) {
$gcode .= $self->gcodegen->extrude($_, 'fill')

View File

@ -12,9 +12,9 @@ use Slic3r::Geometry::Clipper qw(diff_ex union_ex union_pt intersection_ex inter
offset2 union union_pt_chained JT_ROUND JT_SQUARE);
use Slic3r::Print::State ':steps';
has 'config' => (is => 'rw', default => sub { Slic3r::Config::Print->new }, trigger => \&init_config);
has 'default_object_config' => (is => 'rw', default => sub { Slic3r::Config::PrintObject->new });
has 'default_region_config' => (is => 'rw', default => sub { Slic3r::Config::PrintRegion->new });
has 'config' => (is => 'ro', default => sub { Slic3r::Config::Print->new });
has 'default_object_config' => (is => 'ro', default => sub { Slic3r::Config::PrintObject->new });
has 'default_region_config' => (is => 'ro', default => sub { Slic3r::Config::PrintRegion->new });
has 'extra_variables' => (is => 'rw', default => sub {{}});
has 'objects' => (is => 'rw', default => sub {[]});
has 'status_cb' => (is => 'rw');
@ -28,52 +28,12 @@ has 'skirt' => (is => 'rw', default => sub { Slic3r::ExtrusionPath::Collection->
# ordered collection of extrusion paths to build a brim
has 'brim' => (is => 'rw', default => sub { Slic3r::ExtrusionPath::Collection->new });
sub BUILD {
my $self = shift;
# call this manually because the 'default' coderef doesn't trigger the trigger
$self->init_config;
}
# this method needs to be idempotent
sub init_config {
my $self = shift;
# legacy with existing config files
$self->config->set('first_layer_height', $self->config->layer_height)
if !$self->config->first_layer_height;
$self->config->set_ifndef('small_perimeter_speed', $self->config->perimeter_speed);
$self->config->set_ifndef('bridge_speed', $self->config->infill_speed);
$self->config->set_ifndef('solid_infill_speed', $self->config->infill_speed);
$self->config->set_ifndef('top_solid_infill_speed', $self->config->solid_infill_speed);
$self->config->set_ifndef('top_solid_layers', $self->config->solid_layers);
$self->config->set_ifndef('bottom_solid_layers', $self->config->solid_layers);
# G-code flavors
$self->config->set('extrusion_axis', 'A') if $self->config->gcode_flavor eq 'mach3';
$self->config->set('extrusion_axis', '') if $self->config->gcode_flavor eq 'no-extrusion';
# enforce some settings when spiral_vase is set
if ($self->config->spiral_vase) {
$self->config->set('perimeters', 1);
$self->config->set('fill_density', 0);
$self->config->set('top_solid_layers', 0);
$self->config->set('support_material', 0);
$self->config->set('support_material_enforce_layers', 0);
$self->config->set('retract_layer_change', [0]); # TODO: only apply this to the spiral layers
}
# force all retraction lift values to be the same
$self->config->set('retract_lift', [ map $self->config->retract_lift->[0], @{$self->config->retract_lift} ]);
}
sub apply_config {
my ($self, $config) = @_;
$self->config->apply_dynamic($config);
$self->default_object_config->apply_dynamic($config);
$self->default_region_config->apply_dynamic($config);
$self->init_config;
}
sub has_support_material {
@ -261,11 +221,21 @@ sub init_extruders {
}
for my $extruder_id (keys %{{ map {$_ => 1} @used_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(
config => $self->config,
id => $extruder_id,
map { $_ => $self->config->get($_)->[$extruder_id] // $self->config->get($_)->[0] } #/
@{&Slic3r::Extruder::OPTIONS}
use_relative_e_distances => $self->config->use_relative_e_distances,
%extruder_config,
);
}
@ -614,16 +584,17 @@ sub make_skirt {
# skirt may be printed on several layers, having distinct layer heights,
# but loops must be aligned so can't vary width/spacing
# TODO: use each extruder's own flow
my $region0_config = $self->regions->[0]->config;
my $first_layer_height = $self->objects->[0]->config->get_value('first_layer_height');
my $flow = Slic3r::Flow->new(
width => ($self->config->first_layer_extrusion_width || $self->config->perimeter_extrusion_width),
width => ($region0_config->first_layer_extrusion_width || $region0_config->perimeter_extrusion_width),
role => FLOW_ROLE_PERIMETER,
nozzle_diameter => $self->config->nozzle_diameter->[0],
layer_height => $self->config->get_abs_value('first_layer_height'),
layer_height => $first_layer_height,
bridge_flow_ratio => 0,
);
my $spacing = $flow->spacing;
my $first_layer_height = $self->config->get_value('first_layer_height');
my @extruders_e_per_mm = ();
my $extruder_idx = 0;
@ -664,10 +635,10 @@ sub make_brim {
# brim is only printed on first layer and uses support material extruder
my $flow = Slic3r::Flow->new(
width => ($self->config->first_layer_extrusion_width || $self->config->perimeter_extrusion_width),
width => ($self->regions->[0]->config->first_layer_extrusion_width || $self->regions->[0]->config->perimeter_extrusion_width),
role => FLOW_ROLE_PERIMETER,
nozzle_diameter => $self->config->nozzle_diameter->[ $self->config->support_material_extruder-1 ],
layer_height => $self->config->get_abs_value('first_layer_height'),
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'),
bridge_flow_ratio => 0,
);
@ -737,34 +708,28 @@ sub write_gcode {
print $fh "; $_\n" foreach split /\R/, $self->config->notes;
print $fh "\n" if $self->config->notes;
for (qw(layer_height perimeters top_solid_layers bottom_solid_layers fill_density perimeter_speed infill_speed travel_speed)) {
printf $fh "; %s = %s\n", $_, $self->config->$_;
}
for (qw(nozzle_diameter filament_diameter extrusion_multiplier)) {
printf $fh "; %s = %s\n", $_, $self->config->$_->[0];
}
my $layer_height = $self->objects->[0]->config->layer_height;
for my $region_id (0..$#{$self->regions}) {
printf $fh "; perimeters extrusion width = %.2fmm\n",
$self->regions->[$region_id]->flow(FLOW_ROLE_PERIMETER)->width;
$self->regions->[$region_id]->flow(FLOW_ROLE_PERIMETER, $layer_height)->width;
printf $fh "; infill extrusion width = %.2fmm\n",
$self->regions->[$region_id]->flow(FLOW_ROLE_INFILL)->width;
$self->regions->[$region_id]->flow(FLOW_ROLE_INFILL, $layer_height)->width;
printf $fh "; solid infill extrusion width = %.2fmm\n",
$self->regions->[$region_id]->flow(FLOW_ROLE_SOLID_INFILL)->width;
$self->regions->[$region_id]->flow(FLOW_ROLE_SOLID_INFILL, $layer_height)->width;
printf $fh "; top infill extrusion width = %.2fmm\n",
$self->regions->[$region_id]->flow(FLOW_ROLE_TOP_SOLID_INFILL)->width;
$self->regions->[$region_id]->flow(FLOW_ROLE_TOP_SOLID_INFILL, $layer_height)->width;
printf $fh "; support material extrusion width = %.2fmm\n",
$self->objects->[0]->support_material_flow->width
if $self->has_support_material;
printf $fh "; first layer extrusion width = %.2fmm\n",
$self->regions->[$region_id]->flow(FLOW_ROLE_PERIMETER, 0, 1)->width
if ($self->regions->[$region_id]->config->first_layer_extrusion_width != 0);
$self->regions->[$region_id]->flow(FLOW_ROLE_PERIMETER, $layer_height, 0, 1)->width
if ($self->regions->[$region_id]->config->first_layer_extrusion_width ne '0');
print $fh "\n";
}
# set up our extruder object
my $gcodegen = Slic3r::GCode->new(
config => $self->config,
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,
@ -941,13 +906,11 @@ sub write_gcode {
$extruder->absolute_E, $extruder->extruded_volume/1000;
}
if ($self->config->gcode_comments) {
# append full config
print $fh "\n";
foreach my $opt_key (sort @{$self->config->get_keys}) {
next if $Slic3r::Config::Options->{$opt_key}{shortcut};
printf $fh "; %s = %s\n", $opt_key, $self->config->serialize($opt_key);
}
# append full config
print $fh "\n";
foreach my $opt_key (sort @{$self->config->get_keys}) {
next if $Slic3r::Config::Options->{$opt_key}{shortcut};
printf $fh "; %s = %s\n", $opt_key, $self->config->serialize($opt_key);
}
# close our gcode file

View File

@ -521,13 +521,16 @@ sub clip_fill_surfaces {
sub bridge_over_infill {
my $self = shift;
return if $self->config->fill_density == 1;
for my $layer_id (1..$#{$self->layers}) {
my $layer = $self->layers->[$layer_id];
my $lower_layer = $self->layers->[$layer_id-1];
for my $region_id (0..$#{$self->print->regions}) {
my $fill_density = $self->print->regions->[$region_id]->config->fill_density;
next if $fill_density == 1 || $fill_density == 0;
foreach my $layerm (@{$layer->regions}) {
for my $layer_id (1..$#{$self->layers}) {
my $layer = $self->layers->[$layer_id];
my $layerm = $layer->regions->[$region_id];
my $lower_layer = $self->layers->[$layer_id-1];
# compute the areas needing bridge math
my @internal_solid = @{$layerm->fill_surfaces->filter_by_type(S_TYPE_INTERNALSOLID)};
my @lower_internal = map @{$_->fill_surfaces->filter_by_type(S_TYPE_INTERNAL)}, @{$lower_layer->regions};
@ -861,7 +864,8 @@ sub generate_support_material {
&& $self->layer_count >= 2;
my $s = Slic3r::Print::SupportMaterial->new(
config => $self->config,
print_config => $self->print->config,
object_config => $self->config,
flow => $self->support_material_flow,
interface_flow => $self->support_material_flow(FLOW_ROLE_SUPPORT_MATERIAL_INTERFACE),
);

View File

@ -53,7 +53,7 @@ sub flow {
role => $role,
nozzle_diameter => $nozzle_diameter,
layer_height => $layer_height,
bridge_flow_ratio => ($bridge ? $self->config->bridge_flow_ratio : 0),
bridge_flow_ratio => ($bridge ? $self->print->config->bridge_flow_ratio : 0),
);
}

View File

@ -3,13 +3,15 @@ use Moo;
use List::Util qw(sum min max);
use Slic3r::ExtrusionPath ':roles';
use Slic3r::Flow ':roles';
use Slic3r::Geometry qw(scale scaled_epsilon PI rad2deg deg2rad);
use Slic3r::Geometry::Clipper qw(offset diff union union_ex intersection offset_ex offset2
intersection_pl);
use Slic3r::Surface ':types';
has 'config' => (is => 'rw', required => 1);
has 'flow' => (is => 'rw', required => 1);
has 'print_config' => (is => 'rw', required => 1);
has 'object_config' => (is => 'rw', required => 1);
has 'flow' => (is => 'rw', required => 1);
use constant DEBUG_CONTACT_ONLY => 0;
@ -73,8 +75,8 @@ sub contact_area {
# if user specified a custom angle threshold, convert it to radians
my $threshold_rad;
if ($self->config->support_material_threshold) {
$threshold_rad = deg2rad($self->config->support_material_threshold + 1); # +1 makes the threshold inclusive
if ($self->object_config->support_material_threshold) {
$threshold_rad = deg2rad($self->object_config->support_material_threshold + 1); # +1 makes the threshold inclusive
Slic3r::debugf "Threshold angle = %d°\n", rad2deg($threshold_rad);
}
@ -86,9 +88,9 @@ sub contact_area {
# so $layer_id == 0 means first object layer
# and $layer->id == 0 means first print layer (including raft)
if ($self->config->raft_layers == 0) {
if ($self->object_config->raft_layers == 0) {
next if $layer_id == 0;
} elsif (!$self->config->support_material) {
} elsif (!$self->object_config->support_material) {
# if we are only going to generate raft just check
# the 'overhangs' of the first object layer
last if $layer_id > 0;
@ -110,8 +112,8 @@ sub contact_area {
# If a threshold angle was specified, use a different logic for detecting overhangs.
if (defined $threshold_rad
|| $layer_id < $self->config->support_material_enforce_layers
|| $self->config->raft_layers > 0) {
|| $layer_id < $self->object_config->support_material_enforce_layers
|| $self->object_config->raft_layers > 0) {
my $d = defined $threshold_rad
? scale $lower_layer->height * ((cos $threshold_rad) / (sin $threshold_rad))
: 0;
@ -170,8 +172,8 @@ sub contact_area {
# now apply the contact areas to the layer were they need to be made
{
# get the average nozzle diameter used on this layer
my @nozzle_diameters = map $_->nozzle_diameter,
map { $_->perimeter_flow, $_->solid_infill_flow }
my @nozzle_diameters = map $self->print_config->nozzle_diameter->[$_],
map { $_->config->perimeter_extruder-1, $_->config->infill_extruder-1 }
@{$layer->regions};
my $nozzle_diameter = sum(@nozzle_diameters)/@nozzle_diameters;
@ -179,7 +181,7 @@ sub contact_area {
###$contact_z = $layer->print_z - $layer->height;
# ignore this contact area if it's too low
next if $contact_z < $self->config->get_value('first_layer_height');
next if $contact_z < $self->object_config->get_value('first_layer_height');
$contact{$contact_z} = [ @contact ];
$overhang{$contact_z} = [ @overhang ];
@ -242,25 +244,25 @@ sub support_layers_z {
# determine layer height for any non-contact layer
# we use max() to prevent many ultra-thin layers to be inserted in case
# layer_height > nozzle_diameter * 0.75
my $nozzle_diameter = $self->flow->nozzle_diameter;
my $nozzle_diameter = $self->print_config->nozzle_diameter->[$self->object_config->support_material_extruder-1];
my $support_material_height = max($max_object_layer_height, $nozzle_diameter * 0.75);
my @z = sort { $a <=> $b } @$contact_z, @$top_z, (map $_ + $nozzle_diameter, @$top_z);
# enforce first layer height
my $first_layer_height = $self->config->get_value('first_layer_height');
my $first_layer_height = $self->object_config->get_value('first_layer_height');
shift @z while @z && $z[0] <= $first_layer_height;
unshift @z, $first_layer_height;
# add raft layers by dividing the space between first layer and
# first contact layer evenly
if ($self->config->raft_layers > 1 && @z >= 2) {
if ($self->object_config->raft_layers > 1 && @z >= 2) {
# $z[1] is last raft layer (contact layer for the first layer object)
my $height = ($z[1] - $z[0]) / ($self->config->raft_layers - 1);
my $height = ($z[1] - $z[0]) / ($self->object_config->raft_layers - 1);
splice @z, 1, 0,
map { int($_*100)/100 }
map { $z[0] + $height * $_ }
0..($self->config->raft_layers - 1);
0..($self->object_config->raft_layers - 1);
}
for (my $i = $#z; $i >= 0; $i--) {
@ -291,7 +293,7 @@ sub generate_interface_layers {
# let's now generate interface layers below contact areas
my %interface = (); # layer_id => [ polygons ]
my $interface_layers = $self->config->support_material_interface_layers;
my $interface_layers = $self->object_config->support_material_interface_layers;
for my $layer_id (0 .. $#$support_z) {
my $z = $support_z->[$layer_id];
my $this = $contact->{$z} // next;
@ -339,7 +341,7 @@ sub generate_base_layers {
# in case we have no interface layers, look at upper contact
# (1 interface layer means we only have contact layer, so $interface->{$i+1} is empty)
my @upper_contact = ();
if ($self->config->support_material_interface_layers <= 1) {
if ($self->object_config->support_material_interface_layers <= 1) {
@upper_contact = @{ $contact->{$support_z->[$i+1]} || [] };
}
@ -395,8 +397,8 @@ sub generate_toolpaths {
Slic3r::debugf "Generating patterns\n";
# prepare fillers
my $pattern = $self->config->support_material_pattern;
my @angles = ($self->config->support_material_angle);
my $pattern = $self->object_config->support_material_pattern;
my @angles = ($self->object_config->support_material_angle);
if ($pattern eq 'rectilinear-grid') {
$pattern = 'rectilinear';
push @angles, $angles[0] + 90;
@ -407,10 +409,10 @@ sub generate_toolpaths {
support => $object->fill_maker->filler($pattern),
);
my $interface_angle = $self->config->support_material_angle + 90;
my $interface_spacing = $self->config->support_material_interface_spacing + $flow->spacing;
my $interface_angle = $self->object_config->support_material_angle + 90;
my $interface_spacing = $self->object_config->support_material_interface_spacing + $flow->spacing;
my $interface_density = $interface_spacing == 0 ? 1 : $flow->spacing / $interface_spacing;
my $support_spacing = $self->config->support_material_spacing + $flow->spacing;
my $support_spacing = $self->object_config->support_material_spacing + $flow->spacing;
my $support_density = $support_spacing == 0 ? 1 : $flow->spacing / $support_spacing;
my $process_layer = sub {
@ -441,7 +443,7 @@ sub generate_toolpaths {
# contact
my $contact_infill = [];
if ($self->config->support_material_interface_layers == 0) {
if ($self->object_config->support_material_interface_layers == 0) {
# if no interface layers were requested we treat the contact layer
# exactly as a generic base layer
push @$base, @$contact;
@ -561,7 +563,7 @@ sub generate_toolpaths {
# base flange
if ($layer_id == 0) {
$filler = $fillers{interface};
$filler->angle($self->config->support_material_angle + 90);
$filler->angle($self->object_config->support_material_angle + 90);
$density = 0.5;
$flow_spacing = $object->print->first_layer_support_material_flow->spacing;
} else {
@ -609,7 +611,7 @@ sub generate_toolpaths {
};
Slic3r::parallelize(
threads => $self->config->threads,
threads => $self->print_config->threads,
items => [ 0 .. $#{$object->support_layers} ],
thread_cb => sub {
my $q = shift;

View File

@ -99,20 +99,21 @@ sub model {
sub init_print {
my ($model_name, %params) = @_;
my $config = Slic3r::Config->new_from_defaults;
my $config = Slic3r::Config->new;
$config->apply($params{config}) if $params{config};
$config->set('gcode_comments', 1) if $ENV{SLIC3R_TESTS_GCODE};
my $print = Slic3r::Print->new(config => $config);
my $print = Slic3r::Print->new;
$print->apply_config($config);
$model_name = [$model_name] if ref($model_name) ne 'ARRAY';
for my $model (map model($_, %params), @$model_name) {
die "Unknown model in test" if !defined $model;
if (defined $params{duplicate} && $params{duplicate} > 1) {
$model->duplicate($params{duplicate} // 1, $config->min_object_distance);
$model->duplicate($params{duplicate} // 1, $print->config->min_object_distance);
}
$model->arrange_objects($config->min_object_distance);
$model->center_instances_around_point($config->print_center);
$model->arrange_objects($print->config->min_object_distance);
$model->center_instances_around_point($print->config->print_center);
$print->add_model_object($_) for @{$model->objects};
}
$print->validate;

View File

@ -153,12 +153,12 @@ if (@ARGV) { # slicing from command line
}
my $print = Slic3r::Print->new(
config => $config,
status_cb => sub {
my ($percent, $message) = @_;
printf "=> %s\n", $message;
},
);
$print->apply_config($config);
foreach my $model_object (@{$model->objects}) {
$print->auto_assign_extruders($model_object);
$print->add_model_object($model_object);

View File

@ -13,10 +13,14 @@ use Slic3r;
use Slic3r::Test;
sub buffer {
my $config = shift || Slic3r::Config->new_from_defaults;
my $config = shift || Slic3r::Config->new;
my $print_config = Slic3r::Config::Print->new;
$print_config->apply_dynamic($config);
my $buffer = Slic3r::GCode::CoolingBuffer->new(
config => $config,
gcodegen => Slic3r::GCode->new(config => $config, layer_count => 10, extruders => []),
config => $print_config,
gcodegen => Slic3r::GCode->new(print_config => $print_config, layer_count => 10, extruders => []),
);
return $buffer;
}

View File

@ -14,9 +14,8 @@ use Slic3r::Test;
{
my $gcodegen = Slic3r::GCode->new(
config => Slic3r::Config->new_from_defaults,
layer_count => 1,
extruders => [],
layer_count => 1,
extruders => [],
);
$gcodegen->set_shift(10, 10);
is_deeply $gcodegen->last_pos->arrayref, [scale -10, scale -10], 'last_pos is shifted correctly';

View File

@ -140,6 +140,9 @@ use Slic3r::Test;
{
my $config = Slic3r::Config->new_from_defaults;
$config->set('perimeters', 1);
$config->set('fill_density', 0);
$config->set('top_solid_layers', 0);
$config->set('spiral_vase', 1);
$config->set('bottom_solid_layers', 0);
$config->set('skirts', 0);

View File

@ -21,16 +21,16 @@ use Slic3r::Test;
my $test = sub {
my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
$print->init_extruders;
my $flow = $print->support_material_flow;
my $flow = $print->objects->[0]->support_material_flow;
my $support_z = Slic3r::Print::SupportMaterial
->new(config => $config, flow => $flow)
->new(object_config => $print->objects->[0]->config, print_config => $print->config, flow => $flow)
->support_layers_z(\@contact_z, \@top_z, $config->layer_height);
is $support_z->[0], $config->first_layer_height,
'first layer height is honored';
is scalar(grep { $support_z->[$_]-$support_z->[$_-1] <= 0 } 1..$#$support_z), 0,
'no null or negative support layers';
is scalar(grep { $support_z->[$_]-$support_z->[$_-1] > $flow->nozzle_diameter + epsilon } 1..$#$support_z), 0,
is scalar(grep { $support_z->[$_]-$support_z->[$_-1] > $config->nozzle_diameter->[0] + epsilon } 1..$#$support_z), 0,
'no layers thicker than nozzle diameter';
my $wrong_top_spacing = 0;
@ -40,7 +40,7 @@ use Slic3r::Test;
# check that first support layer above this top surface is spaced with nozzle diameter
$wrong_top_spacing = 1
if ($support_z->[$layer_id+1] - $support_z->[$layer_id]) != $flow->nozzle_diameter;
if ($support_z->[$layer_id+1] - $support_z->[$layer_id]) != $config->nozzle_diameter->[0];
}
ok !$wrong_top_spacing, 'layers above top surfaces are spaced correctly';
};

View File

@ -899,6 +899,7 @@ class PrintObjectConfig : public virtual StaticConfig
public:
ConfigOptionFloatOrPercent extrusion_width;
ConfigOptionFloatOrPercent first_layer_height;
ConfigOptionBool infill_only_where_needed;
ConfigOptionFloat layer_height;
ConfigOptionInt raft_layers;
ConfigOptionBool support_material;
@ -921,6 +922,7 @@ class PrintObjectConfig : public virtual StaticConfig
this->extrusion_width.percent = false;
this->first_layer_height.value = 0.35;
this->first_layer_height.percent = false;
this->infill_only_where_needed.value = false;
this->layer_height.value = 0.4;
this->raft_layers.value = 0;
this->support_material.value = false;
@ -941,6 +943,7 @@ class PrintObjectConfig : public virtual StaticConfig
ConfigOption* option(const t_config_option_key opt_key, bool create = false) {
if (opt_key == "extrusion_width") return &this->extrusion_width;
if (opt_key == "first_layer_height") return &this->first_layer_height;
if (opt_key == "infill_only_where_needed") return &this->infill_only_where_needed;
if (opt_key == "layer_height") return &this->layer_height;
if (opt_key == "raft_layers") return &this->raft_layers;
if (opt_key == "support_material") return &this->support_material;
@ -972,7 +975,6 @@ class PrintRegionConfig : public virtual StaticConfig
ConfigOptionInt infill_extruder;
ConfigOptionFloatOrPercent infill_extrusion_width;
ConfigOptionInt infill_every_layers;
ConfigOptionBool infill_only_where_needed;
ConfigOptionInt perimeter_extruder;
ConfigOptionFloatOrPercent perimeter_extrusion_width;
ConfigOptionInt perimeters;
@ -999,7 +1001,6 @@ class PrintRegionConfig : public virtual StaticConfig
this->infill_extrusion_width.value = 0;
this->infill_extrusion_width.percent = false;
this->infill_every_layers.value = 1;
this->infill_only_where_needed.value = false;
this->perimeter_extruder.value = 1;
this->perimeter_extrusion_width.value = 0;
this->perimeter_extrusion_width.percent = false;
@ -1025,7 +1026,6 @@ class PrintRegionConfig : public virtual StaticConfig
if (opt_key == "infill_extruder") return &this->infill_extruder;
if (opt_key == "infill_extrusion_width") return &this->infill_extrusion_width;
if (opt_key == "infill_every_layers") return &this->infill_every_layers;
if (opt_key == "infill_only_where_needed") return &this->infill_only_where_needed;
if (opt_key == "perimeter_extruder") return &this->perimeter_extruder;
if (opt_key == "perimeter_extrusion_width") return &this->perimeter_extrusion_width;
if (opt_key == "perimeters") return &this->perimeters;
@ -1332,6 +1332,15 @@ class PrintConfig : public virtual StaticConfig
return NULL;
};
std::string get_extrusion_axis() {
if (this->gcode_flavor == gcfMach3) {
return std::string("A");
} else if (this->gcode_flavor == gcfNoExtrusion) {
return std::string("");
}
return this->extrusion_axis;
}
};
class DynamicPrintConfig : public DynamicConfig

View File

@ -41,6 +41,7 @@
%code{% THIS->apply(*other, true); %};
std::vector<std::string> get_keys()
%code{% THIS->keys(&RETVAL); %};
std::string get_extrusion_axis();
};
%name{Slic3r::Config::PrintRegion} class PrintRegionConfig {