Satisfy test suite and CLI
This commit is contained in:
parent
e2f1040a76
commit
5bf0942f45
@ -15,18 +15,18 @@ our $Options = print_config_def();
|
|||||||
{
|
{
|
||||||
no strict 'refs';
|
no strict 'refs';
|
||||||
for my $opt_key (keys %$Options) {
|
for my $opt_key (keys %$Options) {
|
||||||
*{$opt_key} = sub { $_[0]->_get($opt_key) };
|
*{$opt_key} = sub { $_[0]->get($opt_key) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub _get {
|
# sub _get {
|
||||||
my ($self, $opt_key) = @_;
|
# my ($self, $opt_key) = @_;
|
||||||
use XXX;
|
# use XXX;
|
||||||
if (!defined first { $_ eq $opt_key } @{$self->get_keys}) {
|
# if (!defined first { $_ eq $opt_key } @{$self->get_keys}) {
|
||||||
ZZZ $opt_key;
|
# ZZZ $opt_key;
|
||||||
}
|
# }
|
||||||
return $self->get($opt_key);
|
# return $self->get($opt_key);
|
||||||
}
|
# }
|
||||||
|
|
||||||
sub new_from_defaults {
|
sub new_from_defaults {
|
||||||
my $class = shift;
|
my $class = shift;
|
||||||
@ -200,7 +200,8 @@ sub diff {
|
|||||||
return [@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 {
|
sub validate {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
|
||||||
@ -317,6 +318,31 @@ sub validate {
|
|||||||
if ($self->perimeter_acceleration || $self->infill_acceleration || $self->bridge_acceleration || $self->first_layer_acceleration)
|
if ($self->perimeter_acceleration || $self->infill_acceleration || $self->bridge_acceleration || $self->first_layer_acceleration)
|
||||||
&& !$self->default_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
|
# general validation, quick and dirty
|
||||||
foreach my $opt_key (@{$self->get_keys}) {
|
foreach my $opt_key (@{$self->get_keys}) {
|
||||||
my $opt = $Options->{$opt_key};
|
my $opt = $Options->{$opt_key};
|
||||||
|
@ -18,7 +18,7 @@ use constant OPTIONS => [qw(
|
|||||||
|
|
||||||
has 'id' => (is => 'rw', required => 1);
|
has 'id' => (is => 'rw', required => 1);
|
||||||
has $_ => (is => 'ro', required => 1) for @{&OPTIONS};
|
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 'E' => (is => 'rw', default => sub {0} );
|
||||||
has 'absolute_E' => (is => 'rw', default => sub {0} );
|
has 'absolute_E' => (is => 'rw', default => sub {0} );
|
||||||
@ -56,7 +56,7 @@ sub scaled_wipe_distance {
|
|||||||
sub extrude {
|
sub extrude {
|
||||||
my ($self, $E) = @_;
|
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);
|
$self->absolute_E($self->absolute_E + $E);
|
||||||
return $self->E($self->E + $E);
|
return $self->E($self->E + $E);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package Slic3r::Fill;
|
package Slic3r::Fill;
|
||||||
use Moo;
|
use Moo;
|
||||||
|
|
||||||
|
use Slic3r::ExtrusionPath ':roles';
|
||||||
use Slic3r::Fill::ArchimedeanChords;
|
use Slic3r::Fill::ArchimedeanChords;
|
||||||
use Slic3r::Fill::Base;
|
use Slic3r::Fill::Base;
|
||||||
use Slic3r::Fill::Concentric;
|
use Slic3r::Fill::Concentric;
|
||||||
@ -11,7 +12,7 @@ use Slic3r::Fill::Line;
|
|||||||
use Slic3r::Fill::OctagramSpiral;
|
use Slic3r::Fill::OctagramSpiral;
|
||||||
use Slic3r::Fill::PlanePath;
|
use Slic3r::Fill::PlanePath;
|
||||||
use Slic3r::Fill::Rectilinear;
|
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 qw(X Y PI scale chained_path);
|
||||||
use Slic3r::Geometry::Clipper qw(union union_ex diff diff_ex intersection_ex offset offset2);
|
use Slic3r::Geometry::Clipper qw(union union_ex diff diff_ex intersection_ex offset offset2);
|
||||||
use Slic3r::Surface ':types';
|
use Slic3r::Surface ':types';
|
||||||
@ -50,7 +51,10 @@ sub make_fill {
|
|||||||
my ($layerm) = @_;
|
my ($layerm) = @_;
|
||||||
|
|
||||||
Slic3r::debugf "Filling layer %d:\n", $layerm->id;
|
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 = ();
|
my @surfaces = ();
|
||||||
|
|
||||||
@ -95,7 +99,7 @@ sub make_fill {
|
|||||||
# we are going to grow such regions by overlapping them with the void (if any)
|
# 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
|
# TODO: detect and investigate whether there could be narrow regions without
|
||||||
# any void neighbors
|
# 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(
|
my $collapsed = diff(
|
||||||
[ map @{$_->expolygon}, @surfaces ],
|
[ map @{$_->expolygon}, @surfaces ],
|
||||||
@ -133,11 +137,10 @@ sub make_fill {
|
|||||||
my $filler = $layerm->config->fill_pattern;
|
my $filler = $layerm->config->fill_pattern;
|
||||||
my $density = $fill_density;
|
my $density = $fill_density;
|
||||||
my $flow = ($surface->surface_type == S_TYPE_TOP)
|
my $flow = ($surface->surface_type == S_TYPE_TOP)
|
||||||
? $layerm->top_infill_flow
|
? $layerm->flow(FLOW_ROLE_TOP_SOLID_INFILL)
|
||||||
: $surface->is_solid
|
: $surface->is_solid
|
||||||
? $layerm->solid_infill_flow
|
? $solid_infill_flow
|
||||||
: $layerm->infill_flow;
|
: $infill_flow;
|
||||||
my $flow_spacing = $flow->spacing;
|
|
||||||
my $is_bridge = $layerm->id > 0 && $surface->is_bridge;
|
my $is_bridge = $layerm->id > 0 && $surface->is_bridge;
|
||||||
my $is_solid = $surface->is_solid;
|
my $is_solid = $surface->is_solid;
|
||||||
|
|
||||||
@ -147,7 +150,7 @@ sub make_fill {
|
|||||||
$filler = $layerm->config->solid_fill_pattern;
|
$filler = $layerm->config->solid_fill_pattern;
|
||||||
if ($is_bridge) {
|
if ($is_bridge) {
|
||||||
$filler = 'rectilinear';
|
$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) {
|
} elsif ($surface->surface_type == S_TYPE_INTERNALSOLID) {
|
||||||
$filler = 'rectilinear';
|
$filler = 'rectilinear';
|
||||||
}
|
}
|
||||||
@ -155,6 +158,8 @@ sub make_fill {
|
|||||||
next SURFACE unless $density > 0;
|
next SURFACE unless $density > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
my $flow_spacing = $flow->spacing;
|
||||||
|
|
||||||
my $f = $self->filler($filler);
|
my $f = $self->filler($filler);
|
||||||
$f->layer_id($layerm->id);
|
$f->layer_id($layerm->id);
|
||||||
$f->angle($layerm->config->fill_angle);
|
$f->angle($layerm->config->fill_angle);
|
||||||
@ -166,7 +171,7 @@ sub make_fill {
|
|||||||
next unless @polylines;
|
next unless @polylines;
|
||||||
|
|
||||||
# ugly hack(tm) to get the right amount of flow (GCode.pm should be fixed)
|
# 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
|
# save into layer
|
||||||
push @fills, my $collection = Slic3r::ExtrusionPath::Collection->new;
|
push @fills, my $collection = Slic3r::ExtrusionPath::Collection->new;
|
||||||
|
@ -36,7 +36,10 @@ sub BUILDARGS {
|
|||||||
$args{width} = $args{layer_height} * $1 / 100;
|
$args{width} = $args{layer_height} * $1 / 100;
|
||||||
}
|
}
|
||||||
$args{spacing} = $self->_spacing(@args{qw(width nozzle_diameter layer_height bridge_flow_ratio)});
|
$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};
|
return {%args};
|
||||||
|
@ -3,11 +3,12 @@ use Moo;
|
|||||||
|
|
||||||
use List::Util qw(min first);
|
use List::Util qw(min first);
|
||||||
use Slic3r::ExtrusionPath ':roles';
|
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 qw(epsilon scale unscale scaled_epsilon points_coincide PI X Y B);
|
||||||
use Slic3r::Geometry::Clipper qw(union_ex);
|
use Slic3r::Geometry::Clipper qw(union_ex);
|
||||||
use Slic3r::Surface ':types';
|
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 'extra_variables' => (is => 'rw', default => sub {{}});
|
||||||
has 'extruders' => (is => 'ro', required => 1);
|
has 'extruders' => (is => 'ro', required => 1);
|
||||||
has 'multiple_extruders' => (is => 'lazy');
|
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 'enable_wipe' => (is => 'lazy'); # at least one extruder has wipe enabled
|
||||||
has 'layer_count' => (is => 'ro', required => 1 );
|
has 'layer_count' => (is => 'ro', required => 1 );
|
||||||
has 'layer' => (is => 'rw');
|
has 'layer' => (is => 'rw');
|
||||||
|
has 'region' => (is => 'rw');
|
||||||
has '_layer_islands' => (is => 'rw');
|
has '_layer_islands' => (is => 'rw');
|
||||||
has '_upper_layer_islands' => (is => 'rw');
|
has '_upper_layer_islands' => (is => 'rw');
|
||||||
has '_layer_overhangs' => (is => 'ro', default => sub { Slic3r::ExPolygon::Collection->new });
|
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 'shift_y' => (is => 'rw', default => sub {0} );
|
||||||
has 'z' => (is => 'rw');
|
has 'z' => (is => 'rw');
|
||||||
has 'speed' => (is => 'rw');
|
has 'speed' => (is => 'rw');
|
||||||
|
has '_extrusion_axis' => (is => 'rw');
|
||||||
|
has '_retract_lift' => (is => 'rw');
|
||||||
|
|
||||||
has 'speeds' => (is => 'lazy'); # mm/min
|
has 'speeds' => (is => 'lazy'); # mm/min
|
||||||
has 'external_mp' => (is => 'rw');
|
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 'last_fan_speed' => (is => 'rw', default => sub {0});
|
||||||
has 'wipe_path' => (is => 'rw');
|
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 {
|
sub _build_speeds {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
return {
|
return {
|
||||||
map { $_ => 60 * $self->config->get_value("${_}_speed") }
|
map { $_ => 60 * $self->print_config->get_value("${_}_speed") }
|
||||||
qw(travel perimeter small_perimeter external_perimeter infill
|
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_BRIDGE => 'bridge',
|
||||||
&EXTR_ROLE_INTERNALBRIDGE => 'solid_infill',
|
&EXTR_ROLE_INTERNALBRIDGE => 'solid_infill',
|
||||||
&EXTR_ROLE_SKIRT => 'perimeter',
|
&EXTR_ROLE_SKIRT => 'perimeter',
|
||||||
&EXTR_ROLE_SUPPORTMATERIAL => 'support_material',
|
|
||||||
&EXTR_ROLE_GAPFILL => 'gap_fill',
|
&EXTR_ROLE_GAPFILL => 'gap_fill',
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -97,29 +107,29 @@ sub change_layer {
|
|||||||
$self->_layer_islands($layer->islands);
|
$self->_layer_islands($layer->islands);
|
||||||
$self->_upper_layer_islands($layer->upper_layer ? $layer->upper_layer->islands : []);
|
$self->_upper_layer_islands($layer->upper_layer ? $layer->upper_layer->islands : []);
|
||||||
$self->_layer_overhangs->clear;
|
$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(
|
$self->_layer_overhangs->append(
|
||||||
# clone ExPolygons because they come from Surface objects but will be used outside here
|
# 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}
|
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(
|
$self->layer_mp(Slic3r::GCode::MotionPlanner->new(
|
||||||
islands => union_ex([ map @$_, @{$layer->slices} ], 1),
|
islands => union_ex([ map @$_, @{$layer->slices} ], 1),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
my $gcode = "";
|
my $gcode = "";
|
||||||
if ($self->config->gcode_flavor =~ /^(?:makerware|sailfish)$/) {
|
if ($self->print_config->gcode_flavor =~ /^(?:makerware|sailfish)$/) {
|
||||||
$gcode .= sprintf "M73 P%s%s\n",
|
$gcode .= sprintf "M73 P%s%s\n",
|
||||||
int(99 * ($layer->id / ($self->layer_count - 1))),
|
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) {
|
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) {
|
} 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 = "";
|
my $gcode = "";
|
||||||
|
|
||||||
$z += $self->config->z_offset;
|
$z += $self->print_config->z_offset;
|
||||||
my $current_z = $self->z;
|
my $current_z = $self->z;
|
||||||
my $nominal_z = defined $current_z ? ($current_z - $self->lifted) : undef;
|
my $nominal_z = defined $current_z ? ($current_z - $self->lifted) : undef;
|
||||||
|
|
||||||
@ -181,11 +191,11 @@ sub extrude_loop {
|
|||||||
# find candidate starting points
|
# find candidate starting points
|
||||||
# start looking for concave vertices not being overhangs
|
# start looking for concave vertices not being overhangs
|
||||||
my @concave = ();
|
my @concave = ();
|
||||||
if ($self->config->start_perimeters_at_concave_points) {
|
if ($self->print_config->start_perimeters_at_concave_points) {
|
||||||
@concave = $polygon->concave_points;
|
@concave = $polygon->concave_points;
|
||||||
}
|
}
|
||||||
my @candidates = ();
|
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;
|
@candidates = grep !$self->_layer_overhangs->contains_point($_), @concave;
|
||||||
}
|
}
|
||||||
if (!@candidates) {
|
if (!@candidates) {
|
||||||
@ -193,7 +203,7 @@ sub extrude_loop {
|
|||||||
@candidates = @concave;
|
@candidates = @concave;
|
||||||
if (!@candidates) {
|
if (!@candidates) {
|
||||||
# if none, look for any non-overhang vertex
|
# 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;
|
@candidates = grep !$self->_layer_overhangs->contains_point($_), @$polygon;
|
||||||
}
|
}
|
||||||
if (!@candidates) {
|
if (!@candidates) {
|
||||||
@ -206,9 +216,9 @@ sub extrude_loop {
|
|||||||
# find the point of the loop that is closest to the current extruder position
|
# find the point of the loop that is closest to the current extruder position
|
||||||
# or randomize if requested
|
# or randomize if requested
|
||||||
my $last_pos = $self->last_pos;
|
my $last_pos = $self->last_pos;
|
||||||
if ($self->config->randomize_start && $loop->role == EXTR_ROLE_CONTOUR_INTERNAL_PERIMETER) {
|
if ($self->print_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 = Slic3r::Point->new(scale $self->print_config->print_center->[X], scale $self->print_config->bed_size->[Y]);
|
||||||
$last_pos->rotate(rand(2*PI), $self->config->print_center);
|
$last_pos->rotate(rand(2*PI), $self->print_config->print_center);
|
||||||
}
|
}
|
||||||
|
|
||||||
# split the loop at the starting point and make a path
|
# split the loop at the starting point and make a path
|
||||||
@ -224,7 +234,7 @@ sub extrude_loop {
|
|||||||
|
|
||||||
my @paths = ();
|
my @paths = ();
|
||||||
# detect overhanging/bridging perimeters
|
# 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
|
# get non-overhang paths by subtracting overhangs from the loop
|
||||||
push @paths,
|
push @paths,
|
||||||
map $_->clone,
|
map $_->clone,
|
||||||
@ -234,7 +244,7 @@ sub extrude_loop {
|
|||||||
push @paths,
|
push @paths,
|
||||||
map {
|
map {
|
||||||
$_->role(EXTR_ROLE_OVERHANG_PERIMETER);
|
$_->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,
|
map $_->clone,
|
||||||
@ -259,7 +269,7 @@ sub extrude_loop {
|
|||||||
$self->wipe_path($extrusion_path->polyline->clone) if $self->enable_wipe;
|
$self->wipe_path($extrusion_path->polyline->clone) if $self->enable_wipe;
|
||||||
|
|
||||||
# make a little move inwards before leaving loop
|
# 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
|
# detect angle between last and first segment
|
||||||
# the side depends on the original winding order of the polygon (left for contours, right for holes)
|
# 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);
|
my @points = $was_clockwise ? (-2, 1) : (1, -2);
|
||||||
@ -299,13 +309,13 @@ sub extrude_path {
|
|||||||
|
|
||||||
# adjust acceleration
|
# adjust acceleration
|
||||||
my $acceleration;
|
my $acceleration;
|
||||||
if (!$self->config->first_layer_acceleration || $self->layer->id != 0) {
|
if (!$self->print_config->first_layer_acceleration || $self->layer->id != 0) {
|
||||||
if ($self->config->perimeter_acceleration && $path->is_perimeter) {
|
if ($self->print_config->perimeter_acceleration && $path->is_perimeter) {
|
||||||
$acceleration = $self->config->perimeter_acceleration;
|
$acceleration = $self->print_config->perimeter_acceleration;
|
||||||
} elsif ($self->config->infill_acceleration && $path->is_fill) {
|
} elsif ($self->print_config->infill_acceleration && $path->is_fill) {
|
||||||
$acceleration = $self->config->infill_acceleration;
|
$acceleration = $self->print_config->infill_acceleration;
|
||||||
} elsif ($self->config->infill_acceleration && $path->is_bridge) {
|
} elsif ($self->print_config->infill_acceleration && $path->is_bridge) {
|
||||||
$acceleration = $self->config->bridge_acceleration;
|
$acceleration = $self->print_config->bridge_acceleration;
|
||||||
}
|
}
|
||||||
$gcode .= $self->set_acceleration($acceleration) if $acceleration;
|
$gcode .= $self->set_acceleration($acceleration) if $acceleration;
|
||||||
}
|
}
|
||||||
@ -322,15 +332,13 @@ sub extrude_path {
|
|||||||
|
|
||||||
# calculate extrusion length per distance unit
|
# calculate extrusion length per distance unit
|
||||||
my $e = $self->extruder->e_per_mm3 * $area;
|
my $e = $self->extruder->e_per_mm3 * $area;
|
||||||
$e = 0 if !$self->config->extrusion_axis;
|
$e = 0 if !$self->_extrusion_axis;
|
||||||
|
|
||||||
# set speed
|
# set speed
|
||||||
$self->speed( $params{speed} || $role_speeds{$path->role} || die "Unknown role: " . $path->role );
|
$self->speed( $params{speed} || $role_speeds{$path->role} || die "Unknown role: " . $path->role );
|
||||||
my $F = $self->speeds->{$self->speed} // $self->speed;
|
my $F = $self->speeds->{$self->speed} // $self->speed;
|
||||||
if ($self->layer->id == 0) {
|
if ($self->layer->id == 0) {
|
||||||
$F = $self->config->first_layer_speed =~ /^(\d+(?:\.\d+)?)%$/
|
$F = $self->print_config->get_abs_value_over('first_layer_speed', $F/60) * 60;
|
||||||
? sprintf("%.3f", $F * $1/100)
|
|
||||||
: $self->config->first_layer_speed * 60;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# extrude arc or line
|
# extrude arc or line
|
||||||
@ -350,12 +358,12 @@ sub extrude_path {
|
|||||||
$gcode .= sprintf "G1 X%.3f Y%.3f",
|
$gcode .= sprintf "G1 X%.3f Y%.3f",
|
||||||
($point->x * &Slic3r::SCALING_FACTOR) + $self->shift_x - $self->extruder->extruder_offset->[X],
|
($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]; #**
|
($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;
|
if $E;
|
||||||
$gcode .= " F$local_F"
|
$gcode .= " F$local_F"
|
||||||
if $local_F;
|
if $local_F;
|
||||||
$gcode .= " ; $description"
|
$gcode .= " ; $description"
|
||||||
if $self->config->gcode_comments;
|
if $self->print_config->gcode_comments;
|
||||||
$gcode .= "\n";
|
$gcode .= "\n";
|
||||||
|
|
||||||
# only include F in the first line
|
# only include F in the first line
|
||||||
@ -369,19 +377,14 @@ sub extrude_path {
|
|||||||
$gcode .= ";_BRIDGE_FAN_END\n" if $path->is_bridge;
|
$gcode .= ";_BRIDGE_FAN_END\n" if $path->is_bridge;
|
||||||
$self->last_pos($path->last_point);
|
$self->last_pos($path->last_point);
|
||||||
|
|
||||||
if ($self->config->cooling) {
|
if ($self->print_config->cooling) {
|
||||||
my $path_time = $path_length / $F * 60;
|
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);
|
$self->elapsed_time($self->elapsed_time + $path_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
# reset acceleration
|
# reset acceleration
|
||||||
$gcode .= $self->set_acceleration($self->config->default_acceleration)
|
$gcode .= $self->set_acceleration($self->print_config->default_acceleration)
|
||||||
if $acceleration && $self->config->default_acceleration;
|
if $acceleration && $self->print_config->default_acceleration;
|
||||||
|
|
||||||
return $gcode;
|
return $gcode;
|
||||||
}
|
}
|
||||||
@ -400,7 +403,7 @@ sub travel_to {
|
|||||||
# skip retraction if the travel move is contained in an island in the current layer
|
# 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)
|
# *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
|
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->_upper_layer_islands})
|
||||||
&& (first { $_->contains_line($travel) } @{$self->_layer_islands}))
|
&& (first { $_->contains_line($travel) } @{$self->_layer_islands}))
|
||||||
|| (defined $role && $role == EXTR_ROLE_SUPPORTMATERIAL && (first { $_->contains_line($travel) } @{$self->layer->support_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->straight_once(0);
|
||||||
$self->speed('travel');
|
$self->speed('travel');
|
||||||
$gcode .= $self->G0($point, undef, 0, $comment || "");
|
$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);
|
$self->straight_once(0);
|
||||||
$gcode .= $self->retract;
|
$gcode .= $self->retract;
|
||||||
$self->speed('travel');
|
$self->speed('travel');
|
||||||
@ -441,7 +444,7 @@ sub _plan {
|
|||||||
my @travel = @{$mp->shortest_path($self->last_pos, $point)->lines};
|
my @travel = @{$mp->shortest_path($self->last_pos, $point)->lines};
|
||||||
|
|
||||||
# if the path is not contained in a single island we need to retract
|
# 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) {
|
if (!$need_retract) {
|
||||||
$need_retract = 1;
|
$need_retract = 1;
|
||||||
foreach my $island (@{$self->_upper_layer_islands}) {
|
foreach my $island (@{$self->_upper_layer_islands}) {
|
||||||
@ -481,14 +484,14 @@ sub retract {
|
|||||||
if ($self->extruder->wipe && $self->wipe_path) {
|
if ($self->extruder->wipe && $self->wipe_path) {
|
||||||
my @points = @{$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 = 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
|
# prepare moves
|
||||||
my $retract = [undef, undef, -$length, $comment];
|
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
|
||||||
: [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
|
# check that we have a positive wipe length
|
||||||
if ($wipe_path) {
|
if ($wipe_path) {
|
||||||
@ -500,7 +503,7 @@ sub retract {
|
|||||||
my $segment_length = $line->length;
|
my $segment_length = $line->length;
|
||||||
# reduce retraction length a bit to avoid effective retraction speed to be greater than the configured one
|
# reduce retraction length a bit to avoid effective retraction speed to be greater than the configured one
|
||||||
# due to rounding
|
# 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;
|
$retracted += $e;
|
||||||
$gcode .= $self->G1($line->b, undef, $e, $retract->[3] . ";_WIPE");
|
$gcode .= $self->G1($line->b, undef, $e, $retract->[3] . ";_WIPE");
|
||||||
}
|
}
|
||||||
@ -510,7 +513,7 @@ sub retract {
|
|||||||
$self->speed('retract');
|
$self->speed('retract');
|
||||||
$gcode .= $self->G1(undef, undef, $retract->[2] - $retracted, $comment);
|
$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";
|
$gcode .= "G10 ; retract\n";
|
||||||
} else {
|
} else {
|
||||||
$self->speed('retract');
|
$self->speed('retract');
|
||||||
@ -518,23 +521,23 @@ sub retract {
|
|||||||
}
|
}
|
||||||
if (!$self->lifted) {
|
if (!$self->lifted) {
|
||||||
$self->speed('travel');
|
$self->speed('travel');
|
||||||
if (defined $params{move_z} && $self->extruder->retract_lift > 0) {
|
if (defined $params{move_z} && $self->_retract_lift > 0) {
|
||||||
my $travel = [undef, $params{move_z} + $self->extruder->retract_lift, 0, 'move to next layer (' . $self->layer->id . ') and lift'];
|
my $travel = [undef, $params{move_z} + $self->_retract_lift, 0, 'move to next layer (' . $self->layer->id . ') and lift'];
|
||||||
$gcode .= $self->G0(@$travel);
|
$gcode .= $self->G0(@$travel);
|
||||||
$self->lifted($self->extruder->retract_lift);
|
$self->lifted($self->_retract_lift);
|
||||||
} elsif ($lift) {
|
} elsif ($lift) {
|
||||||
$gcode .= $self->G1(@$lift);
|
$gcode .= $self->G1(@$lift);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$self->extruder->retracted($self->extruder->retracted + $length);
|
$self->extruder->retracted($self->extruder->retracted + $length);
|
||||||
$self->extruder->restart_extra($restart_extra);
|
$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
|
# reset extrusion distance during retracts
|
||||||
# this makes sure we leave sufficient precision in the firmware
|
# this makes sure we leave sufficient precision in the firmware
|
||||||
$gcode .= $self->reset_e;
|
$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;
|
return $gcode;
|
||||||
}
|
}
|
||||||
@ -543,7 +546,7 @@ sub unretract {
|
|||||||
my ($self) = @_;
|
my ($self) = @_;
|
||||||
|
|
||||||
my $gcode = "";
|
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) {
|
if ($self->lifted) {
|
||||||
$self->speed('travel');
|
$self->speed('travel');
|
||||||
@ -554,15 +557,15 @@ sub unretract {
|
|||||||
my $to_unretract = $self->extruder->retracted + $self->extruder->restart_extra;
|
my $to_unretract = $self->extruder->retracted + $self->extruder->restart_extra;
|
||||||
if ($to_unretract) {
|
if ($to_unretract) {
|
||||||
$self->speed('retract');
|
$self->speed('retract');
|
||||||
if ($self->config->use_firmware_retraction) {
|
if ($self->print_config->use_firmware_retraction) {
|
||||||
$gcode .= "G11 ; unretract\n";
|
$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
|
# use G1 instead of G0 because G0 will blend the restart with the previous travel move
|
||||||
$gcode .= sprintf "G1 %s%.5f F%.3f",
|
$gcode .= sprintf "G1 %s%.5f F%.3f",
|
||||||
$self->config->extrusion_axis,
|
$self->_extrusion_axis,
|
||||||
$self->extruder->extrude($to_unretract),
|
$self->extruder->extrude($to_unretract),
|
||||||
$self->extruder->retract_speed_mm_min;
|
$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";
|
$gcode .= "\n";
|
||||||
}
|
}
|
||||||
$self->extruder->retracted(0);
|
$self->extruder->retracted(0);
|
||||||
@ -574,11 +577,11 @@ sub unretract {
|
|||||||
|
|
||||||
sub reset_e {
|
sub reset_e {
|
||||||
my ($self) = @_;
|
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;
|
$self->extruder->E(0) if $self->extruder;
|
||||||
return sprintf "G92 %s0%s\n", $self->config->extrusion_axis, ($self->config->gcode_comments ? ' ; reset extrusion distance' : '')
|
return sprintf "G92 %s0%s\n", $self->_extrusion_axis, ($self->print_config->gcode_comments ? ' ; reset extrusion distance' : '')
|
||||||
if $self->config->extrusion_axis && !$self->config->use_relative_e_distances;
|
if $self->_extrusion_axis && !$self->print_config->use_relative_e_distances;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub set_acceleration {
|
sub set_acceleration {
|
||||||
@ -586,12 +589,12 @@ sub set_acceleration {
|
|||||||
return "" if !$acceleration;
|
return "" if !$acceleration;
|
||||||
|
|
||||||
return sprintf "M204 S%s%s\n",
|
return sprintf "M204 S%s%s\n",
|
||||||
$acceleration, ($self->config->gcode_comments ? ' ; adjust acceleration' : '');
|
$acceleration, ($self->print_config->gcode_comments ? ' ; adjust acceleration' : '');
|
||||||
}
|
}
|
||||||
|
|
||||||
sub G0 {
|
sub G0 {
|
||||||
my $self = shift;
|
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", @_);
|
return $self->_G0_G1("G0", @_);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -628,11 +631,11 @@ sub _Gx {
|
|||||||
$gcode .= sprintf " F%.3f", $F;
|
$gcode .= sprintf " F%.3f", $F;
|
||||||
|
|
||||||
# output extrusion distance
|
# output extrusion distance
|
||||||
if ($e && $self->config->extrusion_axis) {
|
if ($e && $self->_extrusion_axis) {
|
||||||
$gcode .= sprintf " %s%.5f", $self->config->extrusion_axis, $self->extruder->extrude($e);
|
$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";
|
return "$gcode\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -653,8 +656,8 @@ sub set_extruder {
|
|||||||
$gcode .= $self->retract(toolchange => 1) if defined $self->extruder;
|
$gcode .= $self->retract(toolchange => 1) if defined $self->extruder;
|
||||||
|
|
||||||
# append custom toolchange G-code
|
# append custom toolchange G-code
|
||||||
if (defined $self->extruder && $self->config->toolchange_gcode) {
|
if (defined $self->extruder && $self->print_config->toolchange_gcode) {
|
||||||
$gcode .= sprintf "%s\n", $self->replace_variables($self->config->toolchange_gcode, {
|
$gcode .= sprintf "%s\n", $self->replace_variables($self->print_config->toolchange_gcode, {
|
||||||
previous_extruder => $self->extruder->id,
|
previous_extruder => $self->extruder->id,
|
||||||
next_extruder => $extruder->id,
|
next_extruder => $extruder->id,
|
||||||
});
|
});
|
||||||
@ -669,24 +672,24 @@ sub set_extruder {
|
|||||||
? $self->extruder->first_layer_temperature
|
? $self->extruder->first_layer_temperature
|
||||||
: $self->extruder->temperature;
|
: $self->extruder->temperature;
|
||||||
# we assume that heating is always slower than cooling, so no need to block
|
# 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
|
# set the new extruder
|
||||||
$self->extruder($extruder);
|
$self->extruder($extruder);
|
||||||
$gcode .= sprintf "%s%d%s\n",
|
$gcode .= sprintf "%s%d%s\n",
|
||||||
($self->config->gcode_flavor eq 'makerware'
|
($self->print_config->gcode_flavor eq 'makerware'
|
||||||
? 'M135 T'
|
? 'M135 T'
|
||||||
: $self->config->gcode_flavor eq 'sailfish'
|
: $self->print_config->gcode_flavor eq 'sailfish'
|
||||||
? 'M108 T'
|
? 'M108 T'
|
||||||
: 'T'),
|
: 'T'),
|
||||||
$extruder->id,
|
$extruder->id,
|
||||||
($self->config->gcode_comments ? ' ; change extruder' : '');
|
($self->print_config->gcode_comments ? ' ; change extruder' : '');
|
||||||
|
|
||||||
$gcode .= $self->reset_e;
|
$gcode .= $self->reset_e;
|
||||||
|
|
||||||
# set the new extruder to the operating temperature
|
# 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
|
my $temp = defined $self->layer && $self->layer->id == 0
|
||||||
? $self->extruder->first_layer_temperature
|
? $self->extruder->first_layer_temperature
|
||||||
: $self->extruder->temperature;
|
: $self->extruder->temperature;
|
||||||
@ -702,18 +705,18 @@ sub set_fan {
|
|||||||
if ($self->last_fan_speed != $speed || $dont_save) {
|
if ($self->last_fan_speed != $speed || $dont_save) {
|
||||||
$self->last_fan_speed($speed) if !$dont_save;
|
$self->last_fan_speed($speed) if !$dont_save;
|
||||||
if ($speed == 0) {
|
if ($speed == 0) {
|
||||||
my $code = $self->config->gcode_flavor eq 'teacup'
|
my $code = $self->print_config->gcode_flavor eq 'teacup'
|
||||||
? 'M106 S0'
|
? 'M106 S0'
|
||||||
: $self->config->gcode_flavor =~ /^(?:makerware|sailfish)$/
|
: $self->print_config->gcode_flavor =~ /^(?:makerware|sailfish)$/
|
||||||
? 'M127'
|
? 'M127'
|
||||||
: 'M107';
|
: '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 {
|
} else {
|
||||||
if ($self->config->gcode_flavor =~ /^(?:makerware|sailfish)$/) {
|
if ($self->print_config->gcode_flavor =~ /^(?:makerware|sailfish)$/) {
|
||||||
return sprintf "M126%s\n", ($self->config->gcode_comments ? ' ; enable fan' : '');
|
return sprintf "M126%s\n", ($self->print_config->gcode_comments ? ' ; enable fan' : '');
|
||||||
} else {
|
} else {
|
||||||
return sprintf "M106 %s%d%s\n", ($self->config->gcode_flavor eq 'mach3' ? 'P' : 'S'),
|
return sprintf "M106 %s%d%s\n", ($self->print_config->gcode_flavor eq 'mach3' ? 'P' : 'S'),
|
||||||
(255 * $speed / 100), ($self->config->gcode_comments ? ' ; enable fan' : '');
|
(255 * $speed / 100), ($self->print_config->gcode_comments ? ' ; enable fan' : '');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -723,17 +726,17 @@ sub set_fan {
|
|||||||
sub set_temperature {
|
sub set_temperature {
|
||||||
my ($self, $temperature, $wait, $tool) = @_;
|
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')
|
? ('M109', 'wait for temperature to be reached')
|
||||||
: ('M104', 'set temperature');
|
: ('M104', 'set temperature');
|
||||||
my $gcode = sprintf "$code %s%d %s; $comment\n",
|
my $gcode = sprintf "$code %s%d %s; $comment\n",
|
||||||
($self->config->gcode_flavor eq 'mach3' ? 'P' : 'S'), $temperature,
|
($self->print_config->gcode_flavor eq 'mach3' ? 'P' : 'S'), $temperature,
|
||||||
(defined $tool && ($self->multiple_extruders || $self->config->gcode_flavor =~ /^(?:makerware|sailfish)$/)) ? "T$tool " : "";
|
(defined $tool && ($self->multiple_extruders || $self->print_config->gcode_flavor =~ /^(?:makerware|sailfish)$/)) ? "T$tool " : "";
|
||||||
|
|
||||||
$gcode .= "M116 ; wait for temperature to be reached\n"
|
$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;
|
return $gcode;
|
||||||
}
|
}
|
||||||
@ -741,21 +744,21 @@ sub set_temperature {
|
|||||||
sub set_bed_temperature {
|
sub set_bed_temperature {
|
||||||
my ($self, $temperature, $wait) = @_;
|
my ($self, $temperature, $wait) = @_;
|
||||||
|
|
||||||
my ($code, $comment) = ($wait && $self->config->gcode_flavor ne 'teacup')
|
my ($code, $comment) = ($wait && $self->print_config->gcode_flavor ne 'teacup')
|
||||||
? (($self->config->gcode_flavor =~ /^(?:makerware|sailfish)$/ ? 'M109' : 'M190'), 'wait for bed temperature to be reached')
|
? (($self->print_config->gcode_flavor =~ /^(?:makerware|sailfish)$/ ? 'M109' : 'M190'), 'wait for bed temperature to be reached')
|
||||||
: ('M140', 'set bed temperature');
|
: ('M140', 'set bed temperature');
|
||||||
my $gcode = sprintf "$code %s%d ; $comment\n",
|
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"
|
$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;
|
return $gcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub replace_variables {
|
sub replace_variables {
|
||||||
my ($self, $string, $extra) = @_;
|
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;
|
1;
|
||||||
|
@ -104,7 +104,7 @@ sub flush_path {
|
|||||||
$gcode .= sprintf " I%.3f J%.3f", map { unscale($arc_center->[$_] - $cur_path->[0][$_]) } (X,Y);
|
$gcode .= sprintf " I%.3f J%.3f", map { unscale($arc_center->[$_] - $cur_path->[0][$_]) } (X,Y);
|
||||||
|
|
||||||
my $E = 0; # TODO: compute E using $length
|
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;
|
if $E;
|
||||||
|
|
||||||
my $F = 0; # TODO: extract F from original moves
|
my $F = 0; # TODO: extract F from original moves
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package Slic3r::GCode::CoolingBuffer;
|
package Slic3r::GCode::CoolingBuffer;
|
||||||
use Moo;
|
use Moo;
|
||||||
|
|
||||||
has 'config' => (is => 'ro', required => 1);
|
has 'config' => (is => 'ro', required => 1); # Slic3r::Config::Print
|
||||||
has 'gcodegen' => (is => 'ro', required => 1);
|
has 'gcodegen' => (is => 'ro', required => 1);
|
||||||
has 'gcode' => (is => 'rw', default => sub {""});
|
has 'gcode' => (is => 'rw', default => sub {""});
|
||||||
has 'elapsed_time' => (is => 'rw', default => sub {0});
|
has 'elapsed_time' => (is => 'rw', default => sub {0});
|
||||||
|
@ -19,24 +19,24 @@ has '_last_obj_copy' => (is => 'rw');
|
|||||||
sub _build_spiralvase {
|
sub _build_spiralvase {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
|
||||||
return $self->gcodegen->config->spiral_vase
|
return $self->print->config->spiral_vase
|
||||||
? Slic3r::GCode::SpiralVase->new(config => $self->gcodegen->config)
|
? Slic3r::GCode::SpiralVase->new(config => $self->print->config)
|
||||||
: undef;
|
: undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub _build_vibration_limit {
|
sub _build_vibration_limit {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
|
||||||
return $self->gcodegen->config->vibration_limit
|
return $self->print->config->vibration_limit
|
||||||
? Slic3r::GCode::VibrationLimit->new(config => $self->gcodegen->config)
|
? Slic3r::GCode::VibrationLimit->new(config => $self->print->config)
|
||||||
: undef;
|
: undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub _build_arc_fitting {
|
sub _build_arc_fitting {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
|
||||||
return $self->gcodegen->config->gcode_arcs
|
return $self->print->config->gcode_arcs
|
||||||
? Slic3r::GCode::ArcFitting->new(config => $self->gcodegen->config)
|
? Slic3r::GCode::ArcFitting->new(config => $self->print->config)
|
||||||
: undef;
|
: undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,44 +45,46 @@ sub process_layer {
|
|||||||
my ($layer, $object_copies) = @_;
|
my ($layer, $object_copies) = @_;
|
||||||
my $gcode = "";
|
my $gcode = "";
|
||||||
|
|
||||||
|
my $object = $layer->object;
|
||||||
|
|
||||||
# check whether we're going to apply spiralvase logic
|
# check whether we're going to apply spiralvase logic
|
||||||
my $spiralvase = defined $self->spiralvase
|
my $spiralvase = defined $self->spiralvase
|
||||||
&& ($layer->id > 0 || $self->gcodegen->config->brim_width == 0)
|
&& ($layer->id > 0 || $self->print->config->brim_width == 0)
|
||||||
&& ($layer->id >= $self->gcodegen->config->skirt_height && $self->gcodegen->config->skirt_height != -1)
|
&& ($layer->id >= $self->print->config->skirt_height && $self->print->config->skirt_height != -1)
|
||||||
&& ($layer->id >= $self->gcodegen->config->bottom_solid_layers);
|
&& !defined(first { $_->config->bottom_solid_layers > $layer->id } @{$layer->regions});
|
||||||
|
|
||||||
# if we're going to apply spiralvase to this layer, disable loop clipping
|
# if we're going to apply spiralvase to this layer, disable loop clipping
|
||||||
$self->gcodegen->enable_loop_clipping(!$spiralvase);
|
$self->gcodegen->enable_loop_clipping(!$spiralvase);
|
||||||
|
|
||||||
if (!$self->second_layer_things_done && $layer->id == 1) {
|
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)
|
$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;
|
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)
|
$gcode .= $self->gcodegen->set_bed_temperature($self->print->config->bed_temperature)
|
||||||
if $self->gcodegen->config->bed_temperature && $self->gcodegen->config->bed_temperature != $self->gcodegen->config->first_layer_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);
|
$self->second_layer_things_done(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
# set new layer - this will change Z and force a retraction if retract_layer_change is enabled
|
# 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->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,
|
layer_num => $self->gcodegen->layer->id,
|
||||||
}) . "\n" if $self->gcodegen->config->layer_gcode;
|
}) . "\n" if $self->print->config->layer_gcode;
|
||||||
|
|
||||||
# extrude skirt
|
# 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->skirt_done->{$layer->print_z}) {
|
||||||
$self->gcodegen->set_shift(@{$self->shift});
|
$self->gcodegen->set_shift(@{$self->shift});
|
||||||
$gcode .= $self->gcodegen->set_extruder($self->extruders->[0]);
|
$gcode .= $self->gcodegen->set_extruder($self->extruders->[0]);
|
||||||
# skip skirt if we have a large brim
|
# 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
|
# distribute skirt loops across all extruders
|
||||||
my @skirt_loops = @{$self->print->skirt};
|
my @skirt_loops = @{$self->print->skirt};
|
||||||
for my $i (0 .. $#skirt_loops) {
|
for my $i (0 .. $#skirt_loops) {
|
||||||
# when printing layers > 0 ignore 'min_skirt_length' and
|
# when printing layers > 0 ignore 'min_skirt_length' and
|
||||||
# just use the 'skirts' setting; also just use the current extruder
|
# 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} ])
|
$gcode .= $self->gcodegen->set_extruder($self->extruders->[ ($i/@{$self->extruders}) % @{$self->extruders} ])
|
||||||
if $layer->id == 0;
|
if $layer->id == 0;
|
||||||
$gcode .= $self->gcodegen->extrude_loop($skirt_loops[$i], 'skirt');
|
$gcode .= $self->gcodegen->extrude_loop($skirt_loops[$i], 'skirt');
|
||||||
@ -94,7 +96,7 @@ sub process_layer {
|
|||||||
|
|
||||||
# extrude brim
|
# extrude brim
|
||||||
if (!$self->brim_done) {
|
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});
|
$self->gcodegen->set_shift(@{$self->shift});
|
||||||
$gcode .= $self->gcodegen->extrude_loop($_, 'brim') for @{$self->print->brim};
|
$gcode .= $self->gcodegen->extrude_loop($_, 'brim') for @{$self->print->brim};
|
||||||
$self->brim_done(1);
|
$self->brim_done(1);
|
||||||
@ -109,15 +111,17 @@ sub process_layer {
|
|||||||
|
|
||||||
# extrude support material before other things because it might use a lower Z
|
# 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
|
# 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) {
|
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->set_extruder($self->extruders->[$object->config->support_material_interface_extruder-1]);
|
||||||
$gcode .= $self->gcodegen->extrude_path($_, 'support material interface')
|
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)};
|
for @{$layer->support_interface_fills->chained_path_from($self->gcodegen->last_pos, 0)};
|
||||||
}
|
}
|
||||||
if ($layer->support_fills->count > 0) {
|
if ($layer->support_fills->count > 0) {
|
||||||
$gcode .= $self->gcodegen->set_extruder($self->extruders->[$self->gcodegen->config->support_material_extruder-1]);
|
$gcode .= $self->gcodegen->set_extruder($self->extruders->[$object->config->support_material_extruder-1]);
|
||||||
$gcode .= $self->gcodegen->extrude_path($_, 'support material')
|
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)};
|
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);
|
my @region_ids = 0 .. ($self->print->regions_count-1);
|
||||||
if ($self->gcodegen->multiple_extruders) {
|
if ($self->gcodegen->multiple_extruders) {
|
||||||
my $last_extruder = $self->gcodegen->extruder;
|
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;
|
@region_ids = ($best_region_id, grep $_ != $best_region_id, @region_ids) if $best_region_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach my $region_id (@region_ids) {
|
foreach my $region_id (@region_ids) {
|
||||||
my $layerm = $layer->regions->[$region_id] or next;
|
my $layerm = $layer->regions->[$region_id] or next;
|
||||||
my $region = $self->print->regions->[$region_id];
|
my $region = $self->print->regions->[$region_id];
|
||||||
|
$self->gcodegen->region($region);
|
||||||
|
|
||||||
my @islands = ();
|
my @islands = ();
|
||||||
if ($self->gcodegen->config->avoid_crossing_perimeters) {
|
if ($self->print->config->avoid_crossing_perimeters) {
|
||||||
push @islands, { perimeters => [], fills => [] }
|
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
|
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}) {
|
PERIMETER: foreach my $perimeter (@{$layerm->perimeters}) {
|
||||||
@ -166,8 +171,8 @@ sub process_layer {
|
|||||||
foreach my $island (@islands) {
|
foreach my $island (@islands) {
|
||||||
# give priority to infill if we were already using its extruder and it wouldn't
|
# give priority to infill if we were already using its extruder and it wouldn't
|
||||||
# be good for perimeters
|
# be good for perimeters
|
||||||
if ($self->gcodegen->config->infill_first
|
if ($self->print->config->infill_first
|
||||||
|| ($self->gcodegen->multiple_extruders && $region->extruders->{infill} eq $self->gcodegen->extruder) && $region->extruders->{infill} ne $region->extruders->{perimeter}) {
|
|| ($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_infill($island, $region);
|
||||||
$gcode .= $self->_extrude_perimeters($island, $region);
|
$gcode .= $self->_extrude_perimeters($island, $region);
|
||||||
} else {
|
} else {
|
||||||
@ -184,11 +189,11 @@ sub process_layer {
|
|||||||
|
|
||||||
# apply vibration limit if enabled
|
# apply vibration limit if enabled
|
||||||
$gcode = $self->vibration_limit->process($gcode)
|
$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
|
# apply arc fitting if enabled
|
||||||
$gcode = $self->arc_fitting->process($gcode)
|
$gcode = $self->arc_fitting->process($gcode)
|
||||||
if $self->gcodegen->config->gcode_arcs;
|
if $self->print->config->gcode_arcs;
|
||||||
|
|
||||||
return $gcode;
|
return $gcode;
|
||||||
}
|
}
|
||||||
@ -200,7 +205,7 @@ sub _extrude_perimeters {
|
|||||||
return "" if !@{ $island->{perimeters} };
|
return "" if !@{ $island->{perimeters} };
|
||||||
|
|
||||||
my $gcode = "";
|
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} };
|
$gcode .= $self->gcodegen->extrude($_, 'perimeter') for @{ $island->{perimeters} };
|
||||||
return $gcode;
|
return $gcode;
|
||||||
}
|
}
|
||||||
@ -212,7 +217,7 @@ sub _extrude_infill {
|
|||||||
return "" if !@{ $island->{fills} };
|
return "" if !@{ $island->{fills} };
|
||||||
|
|
||||||
my $gcode = "";
|
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} }) {
|
for my $fill (@{ $island->{fills} }) {
|
||||||
if ($fill->isa('Slic3r::ExtrusionPath::Collection')) {
|
if ($fill->isa('Slic3r::ExtrusionPath::Collection')) {
|
||||||
$gcode .= $self->gcodegen->extrude($_, 'fill')
|
$gcode .= $self->gcodegen->extrude($_, 'fill')
|
||||||
|
@ -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);
|
offset2 union union_pt_chained JT_ROUND JT_SQUARE);
|
||||||
use Slic3r::Print::State ':steps';
|
use Slic3r::Print::State ':steps';
|
||||||
|
|
||||||
has 'config' => (is => 'rw', default => sub { Slic3r::Config::Print->new }, trigger => \&init_config);
|
has 'config' => (is => 'ro', default => sub { Slic3r::Config::Print->new });
|
||||||
has 'default_object_config' => (is => 'rw', default => sub { Slic3r::Config::PrintObject->new });
|
has 'default_object_config' => (is => 'ro', default => sub { Slic3r::Config::PrintObject->new });
|
||||||
has 'default_region_config' => (is => 'rw', default => sub { Slic3r::Config::PrintRegion->new });
|
has 'default_region_config' => (is => 'ro', default => sub { Slic3r::Config::PrintRegion->new });
|
||||||
has 'extra_variables' => (is => 'rw', default => sub {{}});
|
has 'extra_variables' => (is => 'rw', default => sub {{}});
|
||||||
has 'objects' => (is => 'rw', default => sub {[]});
|
has 'objects' => (is => 'rw', default => sub {[]});
|
||||||
has 'status_cb' => (is => 'rw');
|
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
|
# ordered collection of extrusion paths to build a brim
|
||||||
has 'brim' => (is => 'rw', default => sub { Slic3r::ExtrusionPath::Collection->new });
|
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 {
|
sub apply_config {
|
||||||
my ($self, $config) = @_;
|
my ($self, $config) = @_;
|
||||||
|
|
||||||
$self->config->apply_dynamic($config);
|
$self->config->apply_dynamic($config);
|
||||||
$self->default_object_config->apply_dynamic($config);
|
$self->default_object_config->apply_dynamic($config);
|
||||||
$self->default_region_config->apply_dynamic($config);
|
$self->default_region_config->apply_dynamic($config);
|
||||||
$self->init_config;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub has_support_material {
|
sub has_support_material {
|
||||||
@ -261,11 +221,21 @@ sub init_extruders {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for my $extruder_id (keys %{{ map {$_ => 1} @used_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(
|
$self->extruders->[$extruder_id] = Slic3r::Extruder->new(
|
||||||
config => $self->config,
|
|
||||||
id => $extruder_id,
|
id => $extruder_id,
|
||||||
map { $_ => $self->config->get($_)->[$extruder_id] // $self->config->get($_)->[0] } #/
|
use_relative_e_distances => $self->config->use_relative_e_distances,
|
||||||
@{&Slic3r::Extruder::OPTIONS}
|
%extruder_config,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -614,16 +584,17 @@ sub make_skirt {
|
|||||||
# skirt may be printed on several layers, having distinct layer heights,
|
# skirt may be printed on several layers, having distinct layer heights,
|
||||||
# but loops must be aligned so can't vary width/spacing
|
# but loops must be aligned so can't vary width/spacing
|
||||||
# TODO: use each extruder's own flow
|
# 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(
|
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,
|
role => FLOW_ROLE_PERIMETER,
|
||||||
nozzle_diameter => $self->config->nozzle_diameter->[0],
|
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,
|
bridge_flow_ratio => 0,
|
||||||
);
|
);
|
||||||
my $spacing = $flow->spacing;
|
my $spacing = $flow->spacing;
|
||||||
|
|
||||||
my $first_layer_height = $self->config->get_value('first_layer_height');
|
|
||||||
my @extruders_e_per_mm = ();
|
my @extruders_e_per_mm = ();
|
||||||
my $extruder_idx = 0;
|
my $extruder_idx = 0;
|
||||||
|
|
||||||
@ -664,10 +635,10 @@ sub make_brim {
|
|||||||
|
|
||||||
# brim is only printed on first layer and uses support material extruder
|
# brim is only printed on first layer and uses support material extruder
|
||||||
my $flow = Slic3r::Flow->new(
|
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,
|
role => FLOW_ROLE_PERIMETER,
|
||||||
nozzle_diameter => $self->config->nozzle_diameter->[ $self->config->support_material_extruder-1 ],
|
nozzle_diameter => $self->config->nozzle_diameter->[ $self->objects->[0]->config->support_material_extruder-1 ],
|
||||||
layer_height => $self->config->get_abs_value('first_layer_height'),
|
layer_height => $self->objects->[0]->config->get_abs_value('first_layer_height'),
|
||||||
bridge_flow_ratio => 0,
|
bridge_flow_ratio => 0,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -737,34 +708,28 @@ sub write_gcode {
|
|||||||
print $fh "; $_\n" foreach split /\R/, $self->config->notes;
|
print $fh "; $_\n" foreach split /\R/, $self->config->notes;
|
||||||
print $fh "\n" if $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)) {
|
my $layer_height = $self->objects->[0]->config->layer_height;
|
||||||
printf $fh "; %s = %s\n", $_, $self->config->$_;
|
|
||||||
}
|
|
||||||
for (qw(nozzle_diameter filament_diameter extrusion_multiplier)) {
|
|
||||||
printf $fh "; %s = %s\n", $_, $self->config->$_->[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
for my $region_id (0..$#{$self->regions}) {
|
for my $region_id (0..$#{$self->regions}) {
|
||||||
printf $fh "; perimeters extrusion width = %.2fmm\n",
|
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",
|
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",
|
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",
|
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",
|
printf $fh "; support material extrusion width = %.2fmm\n",
|
||||||
$self->objects->[0]->support_material_flow->width
|
$self->objects->[0]->support_material_flow->width
|
||||||
if $self->has_support_material;
|
if $self->has_support_material;
|
||||||
printf $fh "; first layer extrusion width = %.2fmm\n",
|
printf $fh "; first layer extrusion width = %.2fmm\n",
|
||||||
$self->regions->[$region_id]->flow(FLOW_ROLE_PERIMETER, 0, 1)->width
|
$self->regions->[$region_id]->flow(FLOW_ROLE_PERIMETER, $layer_height, 0, 1)->width
|
||||||
if ($self->regions->[$region_id]->config->first_layer_extrusion_width != 0);
|
if ($self->regions->[$region_id]->config->first_layer_extrusion_width ne '0');
|
||||||
print $fh "\n";
|
print $fh "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
# set up our extruder object
|
# set up our extruder object
|
||||||
my $gcodegen = Slic3r::GCode->new(
|
my $gcodegen = Slic3r::GCode->new(
|
||||||
config => $self->config,
|
print_config => $self->config,
|
||||||
extra_variables => $self->extra_variables,
|
extra_variables => $self->extra_variables,
|
||||||
extruders => $self->extruders, # we should only pass the *used* extruders (but maintain the Tx indices right!)
|
extruders => $self->extruders, # we should only pass the *used* extruders (but maintain the Tx indices right!)
|
||||||
layer_count => $self->layer_count,
|
layer_count => $self->layer_count,
|
||||||
@ -941,13 +906,11 @@ sub write_gcode {
|
|||||||
$extruder->absolute_E, $extruder->extruded_volume/1000;
|
$extruder->absolute_E, $extruder->extruded_volume/1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($self->config->gcode_comments) {
|
# append full config
|
||||||
# append full config
|
print $fh "\n";
|
||||||
print $fh "\n";
|
foreach my $opt_key (sort @{$self->config->get_keys}) {
|
||||||
foreach my $opt_key (sort @{$self->config->get_keys}) {
|
next if $Slic3r::Config::Options->{$opt_key}{shortcut};
|
||||||
next if $Slic3r::Config::Options->{$opt_key}{shortcut};
|
printf $fh "; %s = %s\n", $opt_key, $self->config->serialize($opt_key);
|
||||||
printf $fh "; %s = %s\n", $opt_key, $self->config->serialize($opt_key);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# close our gcode file
|
# close our gcode file
|
||||||
|
@ -521,13 +521,16 @@ sub clip_fill_surfaces {
|
|||||||
|
|
||||||
sub bridge_over_infill {
|
sub bridge_over_infill {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
return if $self->config->fill_density == 1;
|
|
||||||
|
|
||||||
for my $layer_id (1..$#{$self->layers}) {
|
for my $region_id (0..$#{$self->print->regions}) {
|
||||||
my $layer = $self->layers->[$layer_id];
|
my $fill_density = $self->print->regions->[$region_id]->config->fill_density;
|
||||||
my $lower_layer = $self->layers->[$layer_id-1];
|
next if $fill_density == 1 || $fill_density == 0;
|
||||||
|
|
||||||
|
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];
|
||||||
|
|
||||||
foreach my $layerm (@{$layer->regions}) {
|
|
||||||
# compute the areas needing bridge math
|
# compute the areas needing bridge math
|
||||||
my @internal_solid = @{$layerm->fill_surfaces->filter_by_type(S_TYPE_INTERNALSOLID)};
|
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};
|
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;
|
&& $self->layer_count >= 2;
|
||||||
|
|
||||||
my $s = Slic3r::Print::SupportMaterial->new(
|
my $s = Slic3r::Print::SupportMaterial->new(
|
||||||
config => $self->config,
|
print_config => $self->print->config,
|
||||||
|
object_config => $self->config,
|
||||||
flow => $self->support_material_flow,
|
flow => $self->support_material_flow,
|
||||||
interface_flow => $self->support_material_flow(FLOW_ROLE_SUPPORT_MATERIAL_INTERFACE),
|
interface_flow => $self->support_material_flow(FLOW_ROLE_SUPPORT_MATERIAL_INTERFACE),
|
||||||
);
|
);
|
||||||
|
@ -53,7 +53,7 @@ sub flow {
|
|||||||
role => $role,
|
role => $role,
|
||||||
nozzle_diameter => $nozzle_diameter,
|
nozzle_diameter => $nozzle_diameter,
|
||||||
layer_height => $layer_height,
|
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),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,13 +3,15 @@ use Moo;
|
|||||||
|
|
||||||
use List::Util qw(sum min max);
|
use List::Util qw(sum min max);
|
||||||
use Slic3r::ExtrusionPath ':roles';
|
use Slic3r::ExtrusionPath ':roles';
|
||||||
|
use Slic3r::Flow ':roles';
|
||||||
use Slic3r::Geometry qw(scale scaled_epsilon PI rad2deg deg2rad);
|
use Slic3r::Geometry qw(scale scaled_epsilon PI rad2deg deg2rad);
|
||||||
use Slic3r::Geometry::Clipper qw(offset diff union union_ex intersection offset_ex offset2
|
use Slic3r::Geometry::Clipper qw(offset diff union union_ex intersection offset_ex offset2
|
||||||
intersection_pl);
|
intersection_pl);
|
||||||
use Slic3r::Surface ':types';
|
use Slic3r::Surface ':types';
|
||||||
|
|
||||||
has 'config' => (is => 'rw', required => 1);
|
has 'print_config' => (is => 'rw', required => 1);
|
||||||
has 'flow' => (is => 'rw', required => 1);
|
has 'object_config' => (is => 'rw', required => 1);
|
||||||
|
has 'flow' => (is => 'rw', required => 1);
|
||||||
|
|
||||||
use constant DEBUG_CONTACT_ONLY => 0;
|
use constant DEBUG_CONTACT_ONLY => 0;
|
||||||
|
|
||||||
@ -73,8 +75,8 @@ sub contact_area {
|
|||||||
|
|
||||||
# if user specified a custom angle threshold, convert it to radians
|
# if user specified a custom angle threshold, convert it to radians
|
||||||
my $threshold_rad;
|
my $threshold_rad;
|
||||||
if ($self->config->support_material_threshold) {
|
if ($self->object_config->support_material_threshold) {
|
||||||
$threshold_rad = deg2rad($self->config->support_material_threshold + 1); # +1 makes the threshold inclusive
|
$threshold_rad = deg2rad($self->object_config->support_material_threshold + 1); # +1 makes the threshold inclusive
|
||||||
Slic3r::debugf "Threshold angle = %d°\n", rad2deg($threshold_rad);
|
Slic3r::debugf "Threshold angle = %d°\n", rad2deg($threshold_rad);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,9 +88,9 @@ sub contact_area {
|
|||||||
# so $layer_id == 0 means first object layer
|
# so $layer_id == 0 means first object layer
|
||||||
# and $layer->id == 0 means first print layer (including raft)
|
# 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;
|
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
|
# if we are only going to generate raft just check
|
||||||
# the 'overhangs' of the first object layer
|
# the 'overhangs' of the first object layer
|
||||||
last if $layer_id > 0;
|
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 a threshold angle was specified, use a different logic for detecting overhangs.
|
||||||
if (defined $threshold_rad
|
if (defined $threshold_rad
|
||||||
|| $layer_id < $self->config->support_material_enforce_layers
|
|| $layer_id < $self->object_config->support_material_enforce_layers
|
||||||
|| $self->config->raft_layers > 0) {
|
|| $self->object_config->raft_layers > 0) {
|
||||||
my $d = defined $threshold_rad
|
my $d = defined $threshold_rad
|
||||||
? scale $lower_layer->height * ((cos $threshold_rad) / (sin $threshold_rad))
|
? scale $lower_layer->height * ((cos $threshold_rad) / (sin $threshold_rad))
|
||||||
: 0;
|
: 0;
|
||||||
@ -170,8 +172,8 @@ sub contact_area {
|
|||||||
# now apply the contact areas to the layer were they need to be made
|
# now apply the contact areas to the layer were they need to be made
|
||||||
{
|
{
|
||||||
# get the average nozzle diameter used on this layer
|
# get the average nozzle diameter used on this layer
|
||||||
my @nozzle_diameters = map $_->nozzle_diameter,
|
my @nozzle_diameters = map $self->print_config->nozzle_diameter->[$_],
|
||||||
map { $_->perimeter_flow, $_->solid_infill_flow }
|
map { $_->config->perimeter_extruder-1, $_->config->infill_extruder-1 }
|
||||||
@{$layer->regions};
|
@{$layer->regions};
|
||||||
my $nozzle_diameter = sum(@nozzle_diameters)/@nozzle_diameters;
|
my $nozzle_diameter = sum(@nozzle_diameters)/@nozzle_diameters;
|
||||||
|
|
||||||
@ -179,7 +181,7 @@ sub contact_area {
|
|||||||
###$contact_z = $layer->print_z - $layer->height;
|
###$contact_z = $layer->print_z - $layer->height;
|
||||||
|
|
||||||
# ignore this contact area if it's too low
|
# 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 ];
|
$contact{$contact_z} = [ @contact ];
|
||||||
$overhang{$contact_z} = [ @overhang ];
|
$overhang{$contact_z} = [ @overhang ];
|
||||||
@ -242,25 +244,25 @@ sub support_layers_z {
|
|||||||
# determine layer height for any non-contact layer
|
# determine layer height for any non-contact layer
|
||||||
# we use max() to prevent many ultra-thin layers to be inserted in case
|
# we use max() to prevent many ultra-thin layers to be inserted in case
|
||||||
# layer_height > nozzle_diameter * 0.75
|
# 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 $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);
|
my @z = sort { $a <=> $b } @$contact_z, @$top_z, (map $_ + $nozzle_diameter, @$top_z);
|
||||||
|
|
||||||
# enforce first layer height
|
# 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;
|
shift @z while @z && $z[0] <= $first_layer_height;
|
||||||
unshift @z, $first_layer_height;
|
unshift @z, $first_layer_height;
|
||||||
|
|
||||||
# add raft layers by dividing the space between first layer and
|
# add raft layers by dividing the space between first layer and
|
||||||
# first contact layer evenly
|
# 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)
|
# $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,
|
splice @z, 1, 0,
|
||||||
map { int($_*100)/100 }
|
map { int($_*100)/100 }
|
||||||
map { $z[0] + $height * $_ }
|
map { $z[0] + $height * $_ }
|
||||||
0..($self->config->raft_layers - 1);
|
0..($self->object_config->raft_layers - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (my $i = $#z; $i >= 0; $i--) {
|
for (my $i = $#z; $i >= 0; $i--) {
|
||||||
@ -291,7 +293,7 @@ sub generate_interface_layers {
|
|||||||
|
|
||||||
# let's now generate interface layers below contact areas
|
# let's now generate interface layers below contact areas
|
||||||
my %interface = (); # layer_id => [ polygons ]
|
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) {
|
for my $layer_id (0 .. $#$support_z) {
|
||||||
my $z = $support_z->[$layer_id];
|
my $z = $support_z->[$layer_id];
|
||||||
my $this = $contact->{$z} // next;
|
my $this = $contact->{$z} // next;
|
||||||
@ -339,7 +341,7 @@ sub generate_base_layers {
|
|||||||
# in case we have no interface layers, look at upper contact
|
# 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)
|
# (1 interface layer means we only have contact layer, so $interface->{$i+1} is empty)
|
||||||
my @upper_contact = ();
|
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]} || [] };
|
@upper_contact = @{ $contact->{$support_z->[$i+1]} || [] };
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -395,8 +397,8 @@ sub generate_toolpaths {
|
|||||||
Slic3r::debugf "Generating patterns\n";
|
Slic3r::debugf "Generating patterns\n";
|
||||||
|
|
||||||
# prepare fillers
|
# prepare fillers
|
||||||
my $pattern = $self->config->support_material_pattern;
|
my $pattern = $self->object_config->support_material_pattern;
|
||||||
my @angles = ($self->config->support_material_angle);
|
my @angles = ($self->object_config->support_material_angle);
|
||||||
if ($pattern eq 'rectilinear-grid') {
|
if ($pattern eq 'rectilinear-grid') {
|
||||||
$pattern = 'rectilinear';
|
$pattern = 'rectilinear';
|
||||||
push @angles, $angles[0] + 90;
|
push @angles, $angles[0] + 90;
|
||||||
@ -407,10 +409,10 @@ sub generate_toolpaths {
|
|||||||
support => $object->fill_maker->filler($pattern),
|
support => $object->fill_maker->filler($pattern),
|
||||||
);
|
);
|
||||||
|
|
||||||
my $interface_angle = $self->config->support_material_angle + 90;
|
my $interface_angle = $self->object_config->support_material_angle + 90;
|
||||||
my $interface_spacing = $self->config->support_material_interface_spacing + $flow->spacing;
|
my $interface_spacing = $self->object_config->support_material_interface_spacing + $flow->spacing;
|
||||||
my $interface_density = $interface_spacing == 0 ? 1 : $flow->spacing / $interface_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 $support_density = $support_spacing == 0 ? 1 : $flow->spacing / $support_spacing;
|
||||||
|
|
||||||
my $process_layer = sub {
|
my $process_layer = sub {
|
||||||
@ -441,7 +443,7 @@ sub generate_toolpaths {
|
|||||||
|
|
||||||
# contact
|
# contact
|
||||||
my $contact_infill = [];
|
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
|
# if no interface layers were requested we treat the contact layer
|
||||||
# exactly as a generic base layer
|
# exactly as a generic base layer
|
||||||
push @$base, @$contact;
|
push @$base, @$contact;
|
||||||
@ -561,7 +563,7 @@ sub generate_toolpaths {
|
|||||||
# base flange
|
# base flange
|
||||||
if ($layer_id == 0) {
|
if ($layer_id == 0) {
|
||||||
$filler = $fillers{interface};
|
$filler = $fillers{interface};
|
||||||
$filler->angle($self->config->support_material_angle + 90);
|
$filler->angle($self->object_config->support_material_angle + 90);
|
||||||
$density = 0.5;
|
$density = 0.5;
|
||||||
$flow_spacing = $object->print->first_layer_support_material_flow->spacing;
|
$flow_spacing = $object->print->first_layer_support_material_flow->spacing;
|
||||||
} else {
|
} else {
|
||||||
@ -609,7 +611,7 @@ sub generate_toolpaths {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Slic3r::parallelize(
|
Slic3r::parallelize(
|
||||||
threads => $self->config->threads,
|
threads => $self->print_config->threads,
|
||||||
items => [ 0 .. $#{$object->support_layers} ],
|
items => [ 0 .. $#{$object->support_layers} ],
|
||||||
thread_cb => sub {
|
thread_cb => sub {
|
||||||
my $q = shift;
|
my $q = shift;
|
||||||
|
@ -99,20 +99,21 @@ sub model {
|
|||||||
sub init_print {
|
sub init_print {
|
||||||
my ($model_name, %params) = @_;
|
my ($model_name, %params) = @_;
|
||||||
|
|
||||||
my $config = Slic3r::Config->new_from_defaults;
|
my $config = Slic3r::Config->new;
|
||||||
$config->apply($params{config}) if $params{config};
|
$config->apply($params{config}) if $params{config};
|
||||||
$config->set('gcode_comments', 1) if $ENV{SLIC3R_TESTS_GCODE};
|
$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';
|
$model_name = [$model_name] if ref($model_name) ne 'ARRAY';
|
||||||
for my $model (map model($_, %params), @$model_name) {
|
for my $model (map model($_, %params), @$model_name) {
|
||||||
die "Unknown model in test" if !defined $model;
|
die "Unknown model in test" if !defined $model;
|
||||||
if (defined $params{duplicate} && $params{duplicate} > 1) {
|
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->arrange_objects($print->config->min_object_distance);
|
||||||
$model->center_instances_around_point($config->print_center);
|
$model->center_instances_around_point($print->config->print_center);
|
||||||
$print->add_model_object($_) for @{$model->objects};
|
$print->add_model_object($_) for @{$model->objects};
|
||||||
}
|
}
|
||||||
$print->validate;
|
$print->validate;
|
||||||
|
@ -153,12 +153,12 @@ if (@ARGV) { # slicing from command line
|
|||||||
}
|
}
|
||||||
|
|
||||||
my $print = Slic3r::Print->new(
|
my $print = Slic3r::Print->new(
|
||||||
config => $config,
|
|
||||||
status_cb => sub {
|
status_cb => sub {
|
||||||
my ($percent, $message) = @_;
|
my ($percent, $message) = @_;
|
||||||
printf "=> %s\n", $message;
|
printf "=> %s\n", $message;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
$print->apply_config($config);
|
||||||
foreach my $model_object (@{$model->objects}) {
|
foreach my $model_object (@{$model->objects}) {
|
||||||
$print->auto_assign_extruders($model_object);
|
$print->auto_assign_extruders($model_object);
|
||||||
$print->add_model_object($model_object);
|
$print->add_model_object($model_object);
|
||||||
|
10
t/cooling.t
10
t/cooling.t
@ -13,10 +13,14 @@ use Slic3r;
|
|||||||
use Slic3r::Test;
|
use Slic3r::Test;
|
||||||
|
|
||||||
sub buffer {
|
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(
|
my $buffer = Slic3r::GCode::CoolingBuffer->new(
|
||||||
config => $config,
|
config => $print_config,
|
||||||
gcodegen => Slic3r::GCode->new(config => $config, layer_count => 10, extruders => []),
|
gcodegen => Slic3r::GCode->new(print_config => $print_config, layer_count => 10, extruders => []),
|
||||||
);
|
);
|
||||||
return $buffer;
|
return $buffer;
|
||||||
}
|
}
|
||||||
|
@ -14,9 +14,8 @@ use Slic3r::Test;
|
|||||||
|
|
||||||
{
|
{
|
||||||
my $gcodegen = Slic3r::GCode->new(
|
my $gcodegen = Slic3r::GCode->new(
|
||||||
config => Slic3r::Config->new_from_defaults,
|
layer_count => 1,
|
||||||
layer_count => 1,
|
extruders => [],
|
||||||
extruders => [],
|
|
||||||
);
|
);
|
||||||
$gcodegen->set_shift(10, 10);
|
$gcodegen->set_shift(10, 10);
|
||||||
is_deeply $gcodegen->last_pos->arrayref, [scale -10, scale -10], 'last_pos is shifted correctly';
|
is_deeply $gcodegen->last_pos->arrayref, [scale -10, scale -10], 'last_pos is shifted correctly';
|
||||||
|
@ -140,6 +140,9 @@ use Slic3r::Test;
|
|||||||
|
|
||||||
{
|
{
|
||||||
my $config = Slic3r::Config->new_from_defaults;
|
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('spiral_vase', 1);
|
||||||
$config->set('bottom_solid_layers', 0);
|
$config->set('bottom_solid_layers', 0);
|
||||||
$config->set('skirts', 0);
|
$config->set('skirts', 0);
|
||||||
|
@ -21,16 +21,16 @@ use Slic3r::Test;
|
|||||||
my $test = sub {
|
my $test = sub {
|
||||||
my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
|
my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
|
||||||
$print->init_extruders;
|
$print->init_extruders;
|
||||||
my $flow = $print->support_material_flow;
|
my $flow = $print->objects->[0]->support_material_flow;
|
||||||
my $support_z = Slic3r::Print::SupportMaterial
|
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);
|
->support_layers_z(\@contact_z, \@top_z, $config->layer_height);
|
||||||
|
|
||||||
is $support_z->[0], $config->first_layer_height,
|
is $support_z->[0], $config->first_layer_height,
|
||||||
'first layer height is honored';
|
'first layer height is honored';
|
||||||
is scalar(grep { $support_z->[$_]-$support_z->[$_-1] <= 0 } 1..$#$support_z), 0,
|
is scalar(grep { $support_z->[$_]-$support_z->[$_-1] <= 0 } 1..$#$support_z), 0,
|
||||||
'no null or negative support layers';
|
'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';
|
'no layers thicker than nozzle diameter';
|
||||||
|
|
||||||
my $wrong_top_spacing = 0;
|
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
|
# check that first support layer above this top surface is spaced with nozzle diameter
|
||||||
$wrong_top_spacing = 1
|
$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';
|
ok !$wrong_top_spacing, 'layers above top surfaces are spaced correctly';
|
||||||
};
|
};
|
||||||
|
@ -899,6 +899,7 @@ class PrintObjectConfig : public virtual StaticConfig
|
|||||||
public:
|
public:
|
||||||
ConfigOptionFloatOrPercent extrusion_width;
|
ConfigOptionFloatOrPercent extrusion_width;
|
||||||
ConfigOptionFloatOrPercent first_layer_height;
|
ConfigOptionFloatOrPercent first_layer_height;
|
||||||
|
ConfigOptionBool infill_only_where_needed;
|
||||||
ConfigOptionFloat layer_height;
|
ConfigOptionFloat layer_height;
|
||||||
ConfigOptionInt raft_layers;
|
ConfigOptionInt raft_layers;
|
||||||
ConfigOptionBool support_material;
|
ConfigOptionBool support_material;
|
||||||
@ -921,6 +922,7 @@ class PrintObjectConfig : public virtual StaticConfig
|
|||||||
this->extrusion_width.percent = false;
|
this->extrusion_width.percent = false;
|
||||||
this->first_layer_height.value = 0.35;
|
this->first_layer_height.value = 0.35;
|
||||||
this->first_layer_height.percent = false;
|
this->first_layer_height.percent = false;
|
||||||
|
this->infill_only_where_needed.value = false;
|
||||||
this->layer_height.value = 0.4;
|
this->layer_height.value = 0.4;
|
||||||
this->raft_layers.value = 0;
|
this->raft_layers.value = 0;
|
||||||
this->support_material.value = false;
|
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) {
|
ConfigOption* option(const t_config_option_key opt_key, bool create = false) {
|
||||||
if (opt_key == "extrusion_width") return &this->extrusion_width;
|
if (opt_key == "extrusion_width") return &this->extrusion_width;
|
||||||
if (opt_key == "first_layer_height") return &this->first_layer_height;
|
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 == "layer_height") return &this->layer_height;
|
||||||
if (opt_key == "raft_layers") return &this->raft_layers;
|
if (opt_key == "raft_layers") return &this->raft_layers;
|
||||||
if (opt_key == "support_material") return &this->support_material;
|
if (opt_key == "support_material") return &this->support_material;
|
||||||
@ -972,7 +975,6 @@ class PrintRegionConfig : public virtual StaticConfig
|
|||||||
ConfigOptionInt infill_extruder;
|
ConfigOptionInt infill_extruder;
|
||||||
ConfigOptionFloatOrPercent infill_extrusion_width;
|
ConfigOptionFloatOrPercent infill_extrusion_width;
|
||||||
ConfigOptionInt infill_every_layers;
|
ConfigOptionInt infill_every_layers;
|
||||||
ConfigOptionBool infill_only_where_needed;
|
|
||||||
ConfigOptionInt perimeter_extruder;
|
ConfigOptionInt perimeter_extruder;
|
||||||
ConfigOptionFloatOrPercent perimeter_extrusion_width;
|
ConfigOptionFloatOrPercent perimeter_extrusion_width;
|
||||||
ConfigOptionInt perimeters;
|
ConfigOptionInt perimeters;
|
||||||
@ -999,7 +1001,6 @@ class PrintRegionConfig : public virtual StaticConfig
|
|||||||
this->infill_extrusion_width.value = 0;
|
this->infill_extrusion_width.value = 0;
|
||||||
this->infill_extrusion_width.percent = false;
|
this->infill_extrusion_width.percent = false;
|
||||||
this->infill_every_layers.value = 1;
|
this->infill_every_layers.value = 1;
|
||||||
this->infill_only_where_needed.value = false;
|
|
||||||
this->perimeter_extruder.value = 1;
|
this->perimeter_extruder.value = 1;
|
||||||
this->perimeter_extrusion_width.value = 0;
|
this->perimeter_extrusion_width.value = 0;
|
||||||
this->perimeter_extrusion_width.percent = false;
|
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_extruder") return &this->infill_extruder;
|
||||||
if (opt_key == "infill_extrusion_width") return &this->infill_extrusion_width;
|
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_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_extruder") return &this->perimeter_extruder;
|
||||||
if (opt_key == "perimeter_extrusion_width") return &this->perimeter_extrusion_width;
|
if (opt_key == "perimeter_extrusion_width") return &this->perimeter_extrusion_width;
|
||||||
if (opt_key == "perimeters") return &this->perimeters;
|
if (opt_key == "perimeters") return &this->perimeters;
|
||||||
@ -1332,6 +1332,15 @@ class PrintConfig : public virtual StaticConfig
|
|||||||
|
|
||||||
return NULL;
|
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
|
class DynamicPrintConfig : public DynamicConfig
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
%code{% THIS->apply(*other, true); %};
|
%code{% THIS->apply(*other, true); %};
|
||||||
std::vector<std::string> get_keys()
|
std::vector<std::string> get_keys()
|
||||||
%code{% THIS->keys(&RETVAL); %};
|
%code{% THIS->keys(&RETVAL); %};
|
||||||
|
std::string get_extrusion_axis();
|
||||||
};
|
};
|
||||||
|
|
||||||
%name{Slic3r::Config::PrintRegion} class PrintRegionConfig {
|
%name{Slic3r::Config::PrintRegion} class PrintRegionConfig {
|
||||||
|
Loading…
Reference in New Issue
Block a user