Make tests pass

This commit is contained in:
Alessandro Ranellucci 2014-01-05 00:36:33 +01:00
parent a2cbb261cb
commit 07b9b12475
16 changed files with 159 additions and 82 deletions

View File

@ -40,8 +40,7 @@ sub new_from_config {
use_relative_e_distances => $config->use_relative_e_distances, use_relative_e_distances => $config->use_relative_e_distances,
); );
foreach my $opt_key (@{&OPTIONS}) { foreach my $opt_key (@{&OPTIONS}) {
my $value = $config->get($opt_key); $conf{$opt_key} = $config->get_at($opt_key, $extruder_id);
$conf{$opt_key} = $value->[$extruder_id] // $value->[0];
} }
return $class->new(%conf); return $class->new(%conf);
} }

View File

@ -72,7 +72,7 @@ sub mm3_per_mm {
my $s = $self->spacing; my $s = $self->spacing;
if ($self->bridge) { if ($self->bridge) {
return ($s**2) * PI/4; return ($w**2) * PI/4;
} elsif ($w >= ($self->nozzle_diameter + $h)) { } elsif ($w >= ($self->nozzle_diameter + $h)) {
# rectangle with semicircles at the ends # rectangle with semicircles at the ends
return $w * $h + ($h**2) / 4 * (PI - 4); return $w * $h + ($h**2) / 4 * (PI - 4);
@ -140,7 +140,7 @@ sub _spacing {
if ($bridge_flow_ratio > 0) { if ($bridge_flow_ratio > 0) {
return $width + BRIDGE_EXTRA_SPACING; return $width + BRIDGE_EXTRA_SPACING;
} }
use XXX; ZZZ "here" if !defined $nozzle_diameter;
my $min_flow_spacing; my $min_flow_spacing;
if ($width >= ($nozzle_diameter + $layer_height)) { if ($width >= ($nozzle_diameter + $layer_height)) {
# rectangle with semicircles at the ends # rectangle with semicircles at the ends

View File

@ -12,7 +12,7 @@ has 'print_config' => (is => 'ro', default => sub { Slic3r::Config::Print-
has 'extra_variables' => (is => 'rw', default => sub {{}}); has 'extra_variables' => (is => 'rw', default => sub {{}});
has 'standby_points' => (is => 'rw'); has 'standby_points' => (is => 'rw');
has 'enable_loop_clipping' => (is => 'rw', default => sub {1}); 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 => 'rw', default => sub {0}); # 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 'region' => (is => 'rw');
@ -25,14 +25,13 @@ has 'z' => (is => 'rw');
has 'speed' => (is => 'rw'); has 'speed' => (is => 'rw');
has '_extrusion_axis' => (is => 'rw'); has '_extrusion_axis' => (is => 'rw');
has '_retract_lift' => (is => 'rw'); has '_retract_lift' => (is => 'rw');
has 'extruders' => (is => 'ro', default => sub {[]}); has 'extruders' => (is => 'ro', default => sub {{}});
has 'extruder' => (is => 'rw');
has 'speeds' => (is => 'lazy'); # mm/min has 'speeds' => (is => 'lazy'); # mm/min
has 'external_mp' => (is => 'rw'); has 'external_mp' => (is => 'rw');
has 'layer_mp' => (is => 'rw'); has 'layer_mp' => (is => 'rw');
has 'new_object' => (is => 'rw', default => sub {0}); has 'new_object' => (is => 'rw', default => sub {0});
has 'straight_once' => (is => 'rw', default => sub {1}); has 'straight_once' => (is => 'rw', default => sub {1});
has 'extruder' => (is => 'rw');
has 'elapsed_time' => (is => 'rw', default => sub {0} ); # seconds has 'elapsed_time' => (is => 'rw', default => sub {0} ); # seconds
has 'lifted' => (is => 'rw', default => sub {0} ); has 'lifted' => (is => 'rw', default => sub {0} );
has 'last_pos' => (is => 'rw', default => sub { Slic3r::Point->new(0,0) } ); has 'last_pos' => (is => 'rw', default => sub { Slic3r::Point->new(0,0) } );
@ -52,7 +51,8 @@ sub set_extruders {
my ($self, $extruder_ids) = @_; my ($self, $extruder_ids) = @_;
foreach my $i (@$extruder_ids) { foreach my $i (@$extruder_ids) {
$self->extruders->[$i] = Slic3r::Extruder->new_from_config($self->print_config, $i); $self->extruders->{$i} = my $e = Slic3r::Extruder->new_from_config($self->print_config, $i);
$self->enable_wipe(1) if $e->wipe;
} }
} }
@ -82,12 +82,7 @@ my %role_speeds = (
sub multiple_extruders { sub multiple_extruders {
my $self = shift; my $self = shift;
return @{$self->extruders} > 1; return (keys %{$self->extruders}) > 1;
}
sub _build_enable_wipe {
my $self = shift;
return (first { $_->wipe } @{$self->extruders}) ? 1 : 0;
} }
sub set_shift { sub set_shift {
@ -248,14 +243,12 @@ sub extrude_loop {
@{$extrusion_path->subtract_expolygons($self->_layer_overhangs)}; @{$extrusion_path->subtract_expolygons($self->_layer_overhangs)};
# get overhang paths by intersecting overhangs with the loop # get overhang paths by intersecting overhangs with the loop
push @paths, foreach my $path (@{$extrusion_path->intersect_expolygons($self->_layer_overhangs)}) {
map { $path = $path->clone;
$_->role(EXTR_ROLE_OVERHANG_PERIMETER); $path->role(EXTR_ROLE_OVERHANG_PERIMETER);
$_->mm3_per_mm($self->region->flow(FLOW_ROLE_PERIMETER, undef, 1)->mm3_per_mm(undef)); $path->mm3_per_mm($self->region->flow(FLOW_ROLE_PERIMETER, undef, 1)->mm3_per_mm(undef));
$_ push @paths, $path;
} }
map $_->clone,
@{$extrusion_path->intersect_expolygons($self->_layer_overhangs)};
# reapply the nearest point search for starting point # reapply the nearest point search for starting point
# (clone because the collection gets DESTROY'ed) # (clone because the collection gets DESTROY'ed)
@ -644,7 +637,7 @@ sub set_extruder {
# if we are running a single-extruder setup, just set the extruder and return nothing # if we are running a single-extruder setup, just set the extruder and return nothing
if (!$self->multiple_extruders) { if (!$self->multiple_extruders) {
$self->extruder($self->extruders->[$extruder_id]); $self->extruder($self->extruders->{$extruder_id});
return ""; return "";
} }
@ -673,7 +666,7 @@ sub set_extruder {
} }
# set the new extruder # set the new extruder
$self->extruder($self->extruders->[$extruder_id]); $self->extruder($self->extruders->{$extruder_id});
$gcode .= sprintf "%s%d%s\n", $gcode .= sprintf "%s%d%s\n",
($self->print_config->gcode_flavor eq 'makerware' ($self->print_config->gcode_flavor eq 'makerware'
? 'M135 T' ? 'M135 T'

View File

@ -4,8 +4,8 @@ use Moo;
use List::Util qw(first); use List::Util qw(first);
use Slic3r::Geometry qw(X Y unscale); use Slic3r::Geometry qw(X Y unscale);
has 'print' => (is => 'ro', required => 1, handles => [qw(extruders)]); has 'print' => (is => 'ro', required => 1);
has 'gcodegen' => (is => 'ro', required => 1); has 'gcodegen' => (is => 'ro', required => 1, handles => [qw(extruders)]);
has 'shift' => (is => 'ro', default => sub { [0,0] }); has 'shift' => (is => 'ro', default => sub { [0,0] });
has 'spiralvase' => (is => 'lazy'); has 'spiralvase' => (is => 'lazy');
@ -57,9 +57,10 @@ sub process_layer {
$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->print->config->temperature}) { for my $extruder_id (sort keys %{$self->extruders}) {
$gcode .= $self->gcodegen->set_temperature($self->extruders->[$t]->temperature, 0, $t) my $extruder = $self->extruders->{$extruder_id};
if $self->print->extruders->[$t]->temperature && $self->extruders->[$t]->temperature != $self->extruders->[$t]->first_layer_temperature; $gcode .= $self->gcodegen->set_temperature($extruder->temperature, 0, $extruder->id)
if $extruder->temperature && $extruder->temperature != $extruder->first_layer_temperature;
} }
$gcode .= $self->gcodegen->set_bed_temperature($self->print->config->bed_temperature) $gcode .= $self->gcodegen->set_bed_temperature($self->print->config->bed_temperature)
if $self->print->config->bed_temperature && $self->print->config->bed_temperature != $self->print->config->first_layer_bed_temperature; if $self->print->config->bed_temperature && $self->print->config->bed_temperature != $self->print->config->first_layer_bed_temperature;
@ -76,7 +77,8 @@ sub process_layer {
if (((values %{$self->skirt_done}) < $self->print->config->skirt_height || $self->print->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]); my @extruder_ids = sort keys %{$self->extruders};
$gcode .= $self->gcodegen->set_extruder($extruder_ids[0]);
# skip skirt if we have a large brim # skip skirt if we have a large brim
if ($layer->id < $self->print->config->skirt_height || $self->print->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
@ -85,7 +87,7 @@ sub process_layer {
# 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->print->config->skirts); last if ($layer->id > 0) && ($i >= $self->print->config->skirts);
$gcode .= $self->gcodegen->set_extruder(($i/@{$self->extruders}) % @{$self->extruders}) $gcode .= $self->gcodegen->set_extruder(($i/@extruder_ids) % @extruder_ids)
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');
} }

View File

@ -709,7 +709,7 @@ sub make_brim {
my $flow = Slic3r::Flow->new_from_width( my $flow = Slic3r::Flow->new_from_width(
width => ($self->config->first_layer_extrusion_width || $self->regions->[0]->config->perimeter_extrusion_width), width => ($self->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->objects->[0]->config->support_material_extruder-1 ], nozzle_diameter => $self->config->get_at('nozzle_diameter', $self->objects->[0]->config->support_material_extruder-1),
layer_height => $first_layer_height, layer_height => $first_layer_height,
bridge_flow_ratio => 0, bridge_flow_ratio => 0,
); );
@ -807,7 +807,6 @@ sub write_gcode {
layer_count => $self->layer_count, layer_count => $self->layer_count,
); );
$gcodegen->set_extruders($self->extruders); $gcodegen->set_extruders($self->extruders);
$gcodegen->set_extruder($self->extruders->[0]);
print $fh "G21 ; set units to millimeters\n" if $self->config->gcode_flavor ne 'makerware'; print $fh "G21 ; set units to millimeters\n" if $self->config->gcode_flavor ne 'makerware';
print $fh $gcodegen->set_fan(0, 1) if $self->config->cooling && $self->config->disable_fan_first_layers; print $fh $gcodegen->set_fan(0, 1) if $self->config->cooling && $self->config->disable_fan_first_layers;
@ -822,8 +821,8 @@ sub write_gcode {
my ($wait) = @_; my ($wait) = @_;
return if $self->config->start_gcode =~ /M(?:109|104)/i; return if $self->config->start_gcode =~ /M(?:109|104)/i;
for my $t (0 .. $#{$self->extruders}) { for my $t (@{$self->extruders}) {
my $temp = $self->config->first_layer_temperature->[$t] // $self->config->first_layer_temperature->[0]; my $temp = $self->config->get_at('first_layer_temperature', $t);
$temp += $self->config->standby_temperature_delta if $self->config->ooze_prevention; $temp += $self->config->standby_temperature_delta if $self->config->ooze_prevention;
printf $fh $gcodegen->set_temperature($temp, $wait, $t) if $temp > 0; printf $fh $gcodegen->set_temperature($temp, $wait, $t) if $temp > 0;
} }
@ -873,9 +872,9 @@ sub write_gcode {
if (@skirt_points) { if (@skirt_points) {
my $outer_skirt = convex_hull(\@skirt_points); my $outer_skirt = convex_hull(\@skirt_points);
my @skirts = (); my @skirts = ();
foreach my $extruder (@{$self->extruders}) { foreach my $extruder_id (@{$self->extruders}) {
push @skirts, my $s = $outer_skirt->clone; push @skirts, my $s = $outer_skirt->clone;
$s->translate(map scale($_), @{$extruder->extruder_offset}); $s->translate(map scale($_), @{$self->config->get_at('extruder_offset', $extruder_id)});
} }
my $convex_hull = convex_hull([ map @$_, @skirts ]); my $convex_hull = convex_hull([ map @$_, @skirts ]);
$gcodegen->standby_points([ map $_->clone, map @$_, map $_->subdivide(scale 10), @{offset([$convex_hull], scale 3)} ]); $gcodegen->standby_points([ map $_->clone, map @$_, map $_->subdivide(scale 10), @{offset([$convex_hull], scale 3)} ]);
@ -888,6 +887,9 @@ sub write_gcode {
gcodegen => $gcodegen, gcodegen => $gcodegen,
); );
# set initial extruder only after custom start G-code
print $fh $gcodegen->set_extruder($self->extruders->[0]);
# do all objects for each layer # do all objects for each layer
if ($self->config->complete_objects) { if ($self->config->complete_objects) {
# print objects from the smallest to the tallest to avoid collisions # print objects from the smallest to the tallest to avoid collisions
@ -975,7 +977,7 @@ sub write_gcode {
$self->total_used_filament(0); $self->total_used_filament(0);
$self->total_extruded_volume(0); $self->total_extruded_volume(0);
foreach my $extruder_id (@{$self->extruders}) { foreach my $extruder_id (@{$self->extruders}) {
my $extruder = $gcodegen->extruders->[$extruder_id]; my $extruder = $gcodegen->extruders->{$extruder_id};
$self->total_used_filament($self->total_used_filament + $extruder->absolute_E); $self->total_used_filament($self->total_used_filament + $extruder->absolute_E);
$self->total_extruded_volume($self->total_extruded_volume + $extruder->extruded_volume); $self->total_extruded_volume($self->total_extruded_volume + $extruder->extruded_volume);

View File

@ -758,7 +758,7 @@ sub combine_infill {
my $every = $region->config->infill_every_layers; my $every = $region->config->infill_every_layers;
# limit the number of combined layers to the maximum height allowed by this regions' nozzle # limit the number of combined layers to the maximum height allowed by this regions' nozzle
my $nozzle_diameter = $self->print->config->nozzle_diameter->[ $region->config->infill_extruder-1 ]; my $nozzle_diameter = $self->print->config->get_at('nozzle_diameter', $region->config->infill_extruder-1);
# define the combinations # define the combinations
my @combine = (); # layer_id => thickness in layers my @combine = (); # layer_id => thickness in layers
@ -810,12 +810,12 @@ sub combine_infill {
# so let's remove those areas from all layers # so let's remove those areas from all layers
my @intersection_with_clearance = map @{$_->offset( my @intersection_with_clearance = map @{$_->offset(
$layerms[-1]->solid_infill_flow->scaled_width / 2 $layerms[-1]->flow(FLOW_ROLE_SOLID_INFILL)->scaled_width / 2
+ $layerms[-1]->perimeter_flow->scaled_width / 2 + $layerms[-1]->flow(FLOW_ROLE_PERIMETER)->scaled_width / 2
# Because fill areas for rectilinear and honeycomb are grown # Because fill areas for rectilinear and honeycomb are grown
# later to overlap perimeters, we need to counteract that too. # later to overlap perimeters, we need to counteract that too.
+ (($type == S_TYPE_INTERNALSOLID || $region->config->fill_pattern =~ /(rectilinear|honeycomb)/) + (($type == S_TYPE_INTERNALSOLID || $region->config->fill_pattern =~ /(rectilinear|honeycomb)/)
? $layerms[-1]->solid_infill_flow->scaled_width * &Slic3r::INFILL_OVERLAP_OVER_SPACING ? $layerms[-1]->flow(FLOW_ROLE_SOLID_INFILL)->scaled_width * &Slic3r::INFILL_OVERLAP_OVER_SPACING
: 0) : 0)
)}, @$intersection; )}, @$intersection;
@ -866,7 +866,8 @@ sub generate_support_material {
my $first_layer_flow = Slic3r::Flow->new_from_width( my $first_layer_flow = Slic3r::Flow->new_from_width(
width => ($self->config->first_layer_extrusion_width || $self->config->support_material_extrusion_width), width => ($self->config->first_layer_extrusion_width || $self->config->support_material_extrusion_width),
role => FLOW_ROLE_SUPPORT_MATERIAL, role => FLOW_ROLE_SUPPORT_MATERIAL,
nozzle_diameter => $self->print->config->nozzle_diameter->[ $self->config->support_material_extruder-1 ], nozzle_diameter => $self->print->config->nozzle_diameter->[ $self->config->support_material_extruder-1 ]
// $self->print->config->nozzle_diameter->[0],
layer_height => $self->config->get_abs_value('first_layer_height'), layer_height => $self->config->get_abs_value('first_layer_height'),
bridge_flow_ratio => 0, bridge_flow_ratio => 0,
); );
@ -903,7 +904,7 @@ sub support_material_flow {
return Slic3r::Flow->new_from_width( return Slic3r::Flow->new_from_width(
width => $self->config->support_material_extrusion_width, width => $self->config->support_material_extrusion_width,
role => $role, role => $role,
nozzle_diameter => $self->print->config->nozzle_diameter->[$extruder-1], nozzle_diameter => $self->print->config->nozzle_diameter->[$extruder-1] // $self->print->config->nozzle_diameter->[0],
layer_height => $self->config->layer_height, layer_height => $self->config->layer_height,
bridge_flow_ratio => 0, bridge_flow_ratio => 0,
); );

View File

@ -46,7 +46,7 @@ sub flow {
} else { } else {
die "Unknown role $role"; die "Unknown role $role";
} }
my $nozzle_diameter = $self->print->config->nozzle_diameter->[$extruder-1]; my $nozzle_diameter = $self->print->config->get_at('nozzle_diameter', $extruder-1);
return Slic3r::Flow->new_from_width( return Slic3r::Flow->new_from_width(
width => $config_width, width => $config_width,

View File

@ -174,7 +174,7 @@ 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 $self->print_config->nozzle_diameter->[$_], my @nozzle_diameters = map $self->print_config->get_at('nozzle_diameter', $_),
map { $_->config->perimeter_extruder-1, $_->config->infill_extruder-1 } 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;
@ -246,7 +246,7 @@ 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->print_config->nozzle_diameter->[$self->object_config->support_material_extruder-1]; my $nozzle_diameter = $self->print_config->get_at('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);

View File

@ -11,10 +11,41 @@ use List::Util qw(first);
use Slic3r; use Slic3r;
use Slic3r::Test; use Slic3r::Test;
plan skip_all => 'this test is currently disabled'; # needs to be adapted to the new API plan tests => 2;
plan tests => 3;
{ {
my $config = Slic3r::Config->new_from_defaults;
$config->set('layer_height', 0.2);
$config->set('first_layer_height', 0.2);
$config->set('nozzle_diameter', [0.5]);
$config->set('infill_every_layers', 2);
$config->set('infill_extruder', 2);
$config->set('top_solid_layers', 0);
$config->set('bottom_solid_layers', 0);
my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
ok my $gcode = Slic3r::Test::gcode($print), "infill_every_layers does not crash";
my $tool = undef;
my %layer_infill = (); # layer_z => has_infill
Slic3r::GCode::Reader->new->parse($gcode, sub {
my ($self, $cmd, $args, $info) = @_;
if ($cmd =~ /^T(\d+)/) {
$tool = $1;
} elsif ($cmd eq 'G1' && $info->{extruding} && $info->{dist_XY} > 0) {
$layer_infill{$self->Z} //= 0;
if ($tool == $config->infill_extruder-1) {
$layer_infill{$self->Z} = 1;
}
}
});
my $layers_with_infill = grep $_, values %layer_infill;
$layers_with_infill--; # first layer is never combined
is $layers_with_infill, scalar(keys %layer_infill)/2, 'infill is only present in correct number of layers';
}
# the following needs to be adapted to the new API
if (0) {
my $config = Slic3r::Config->new_from_defaults; my $config = Slic3r::Config->new_from_defaults;
$config->set('skirts', 0); $config->set('skirts', 0);
$config->set('solid_layers', 0); $config->set('solid_layers', 0);

View File

@ -41,8 +41,8 @@ my $test = sub {
if ($info->{dist_Z}) { if ($info->{dist_Z}) {
# lift move or lift + change layer # lift move or lift + change layer
if (_eq($info->{dist_Z}, $print->extruders->[$tool]->retract_lift) if (_eq($info->{dist_Z}, $print->config->get_at('retract_lift', $tool))
|| (_eq($info->{dist_Z}, $conf->layer_height + $print->extruders->[$tool]->retract_lift) && $print->extruders->[$tool]->retract_lift > 0)) { || (_eq($info->{dist_Z}, $conf->layer_height + $print->config->get_at('retract_lift', $tool)) && $print->config->get_at('retract_lift', $tool) > 0)) {
fail 'only lifting while retracted' if !$retracted[$tool] && !($conf->g0 && $info->{retracting}); fail 'only lifting while retracted' if !$retracted[$tool] && !($conf->g0 && $info->{retracting});
fail 'double lift' if $lifted; fail 'double lift' if $lifted;
$lifted = 1; $lifted = 1;
@ -50,8 +50,8 @@ my $test = sub {
if ($info->{dist_Z} < 0) { if ($info->{dist_Z} < 0) {
fail 'going down only after lifting' if !$lifted; fail 'going down only after lifting' if !$lifted;
fail 'going down by the same amount of the lift or by the amount needed to get to next layer' fail 'going down by the same amount of the lift or by the amount needed to get to next layer'
if !_eq($info->{dist_Z}, -$print->extruders->[$tool]->retract_lift) if !_eq($info->{dist_Z}, -$print->config->get_at('retract_lift', $tool))
&& !_eq($info->{dist_Z}, -$print->extruders->[$tool]->retract_lift + $conf->layer_height); && !_eq($info->{dist_Z}, -$print->config->get_at('retract_lift', $tool) + $conf->layer_height);
$lifted = 0; $lifted = 0;
} }
fail 'move Z at travel speed' if ($args->{F} // $self->F) != $conf->travel_speed * 60; fail 'move Z at travel speed' if ($args->{F} // $self->F) != $conf->travel_speed * 60;
@ -59,9 +59,9 @@ my $test = sub {
if ($info->{retracting}) { if ($info->{retracting}) {
$retracted[$tool] = 1; $retracted[$tool] = 1;
$retracted_length[$tool] += -$info->{dist_E}; $retracted_length[$tool] += -$info->{dist_E};
if (_eq($retracted_length[$tool], $print->extruders->[$tool]->retract_length)) { if (_eq($retracted_length[$tool], $print->config->get_at('retract_length', $tool))) {
# okay # okay
} elsif (_eq($retracted_length[$tool], $print->extruders->[$tool]->retract_length_toolchange)) { } elsif (_eq($retracted_length[$tool], $print->config->get_at('retract_length_toolchange', $tool))) {
$wait_for_toolchange = 1; $wait_for_toolchange = 1;
} else { } else {
fail 'retracted by the correct amount'; fail 'retracted by the correct amount';
@ -72,9 +72,9 @@ my $test = sub {
if ($info->{extruding}) { if ($info->{extruding}) {
fail 'only extruding while not lifted' if $lifted; fail 'only extruding while not lifted' if $lifted;
if ($retracted[$tool]) { if ($retracted[$tool]) {
my $expected_amount = $retracted_length[$tool] + $print->extruders->[$tool]->retract_restart_extra; my $expected_amount = $retracted_length[$tool] + $print->config->get_at('retract_restart_extra', $tool);
if ($changed_tool && $toolchange_count[$tool] > 1) { if ($changed_tool && $toolchange_count[$tool] > 1) {
$expected_amount = $print->extruders->[$tool]->retract_length_toolchange + $print->extruders->[$tool]->retract_restart_extra_toolchange; $expected_amount = $print->config->get_at('retract_length_toolchange', $tool) + $print->config->get_at('retract_restart_extra_toolchange', $tool);
$changed_tool = 0; $changed_tool = 0;
} }
fail 'unretracted by the correct amount' fail 'unretracted by the correct amount'
@ -83,7 +83,7 @@ my $test = sub {
$retracted_length[$tool] = 0; $retracted_length[$tool] = 0;
} }
} }
if ($info->{travel} && $info->{dist_XY} >= $print->extruders->[$tool]->retract_before_travel) { if ($info->{travel} && $info->{dist_XY} >= $print->config->get_at('retract_before_travel', $tool)) {
fail 'retracted before long travel move' if !$retracted[$tool]; fail 'retracted before long travel move' if !$retracted[$tool];
} }
}); });

View File

@ -23,7 +23,13 @@ use Slic3r::Test;
$print->init_extruders; $print->init_extruders;
my $flow = $print->objects->[0]->support_material_flow; my $flow = $print->objects->[0]->support_material_flow;
my $support_z = Slic3r::Print::SupportMaterial my $support_z = Slic3r::Print::SupportMaterial
->new(object_config => $print->objects->[0]->config, print_config => $print->config, flow => $flow) ->new(
object_config => $print->objects->[0]->config,
print_config => $print->config,
flow => $flow,
interface_flow => $flow,
first_layer_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,

View File

@ -130,9 +130,9 @@ ConfigBase::get(t_config_option_key opt_key) {
return optv->point.to_SV_pureperl(); return optv->point.to_SV_pureperl();
} else if (ConfigOptionPoints* optv = dynamic_cast<ConfigOptionPoints*>(opt)) { } else if (ConfigOptionPoints* optv = dynamic_cast<ConfigOptionPoints*>(opt)) {
AV* av = newAV(); AV* av = newAV();
av_fill(av, optv->points.size()-1); av_fill(av, optv->values.size()-1);
for (Pointfs::iterator it = optv->points.begin(); it != optv->points.end(); ++it) for (Pointfs::iterator it = optv->values.begin(); it != optv->values.end(); ++it)
av_store(av, it - optv->points.begin(), it->to_SV_pureperl()); av_store(av, it - optv->values.begin(), it->to_SV_pureperl());
return newRV_noinc((SV*)av); return newRV_noinc((SV*)av);
} else if (ConfigOptionBool* optv = dynamic_cast<ConfigOptionBool*>(opt)) { } else if (ConfigOptionBool* optv = dynamic_cast<ConfigOptionBool*>(opt)) {
return newSViv(optv->value ? 1 : 0); return newSViv(optv->value ? 1 : 0);
@ -148,6 +148,28 @@ ConfigBase::get(t_config_option_key opt_key) {
} }
} }
SV*
ConfigBase::get_at(t_config_option_key opt_key, size_t i) {
ConfigOption* opt = this->option(opt_key);
if (opt == NULL) return &PL_sv_undef;
if (ConfigOptionFloats* optv = dynamic_cast<ConfigOptionFloats*>(opt)) {
return newSVnv(optv->get_at(i));
} else if (ConfigOptionInts* optv = dynamic_cast<ConfigOptionInts*>(opt)) {
return newSViv(optv->get_at(i));
} else if (ConfigOptionStrings* optv = dynamic_cast<ConfigOptionStrings*>(opt)) {
// we don't serialize() because that would escape newlines
std::string val = optv->get_at(i);
return newSVpvn(val.c_str(), val.length());
} else if (ConfigOptionPoints* optv = dynamic_cast<ConfigOptionPoints*>(opt)) {
return optv->get_at(i).to_SV_pureperl();
} else if (ConfigOptionBools* optv = dynamic_cast<ConfigOptionBools*>(opt)) {
return newSViv(optv->get_at(i) ? 1 : 0);
} else {
return &PL_sv_undef;
}
}
void void
ConfigBase::set(t_config_option_key opt_key, SV* value) { ConfigBase::set(t_config_option_key opt_key, SV* value) {
ConfigOption* opt = this->option(opt_key, true); ConfigOption* opt = this->option(opt_key, true);
@ -193,14 +215,14 @@ ConfigBase::set(t_config_option_key opt_key, SV* value) {
} else if (ConfigOptionPoint* optv = dynamic_cast<ConfigOptionPoint*>(opt)) { } else if (ConfigOptionPoint* optv = dynamic_cast<ConfigOptionPoint*>(opt)) {
optv->point.from_SV(value); optv->point.from_SV(value);
} else if (ConfigOptionPoints* optv = dynamic_cast<ConfigOptionPoints*>(opt)) { } else if (ConfigOptionPoints* optv = dynamic_cast<ConfigOptionPoints*>(opt)) {
optv->points.clear(); optv->values.clear();
AV* av = (AV*)SvRV(value); AV* av = (AV*)SvRV(value);
const size_t len = av_len(av)+1; const size_t len = av_len(av)+1;
for (size_t i = 0; i < len; i++) { for (size_t i = 0; i < len; i++) {
SV** elem = av_fetch(av, i, 0); SV** elem = av_fetch(av, i, 0);
Pointf point; Pointf point;
point.from_SV(*elem); point.from_SV(*elem);
optv->points.push_back(point); optv->values.push_back(point);
} }
} else if (ConfigOptionBool* optv = dynamic_cast<ConfigOptionBool*>(opt)) { } else if (ConfigOptionBool* optv = dynamic_cast<ConfigOptionBool*>(opt)) {
optv->value = SvTRUE(value); optv->value = SvTRUE(value);

View File

@ -8,6 +8,7 @@
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <iostream> #include <iostream>
#include <stdexcept>
#include <string> #include <string>
#include <vector> #include <vector>
#include "Point.hpp" #include "Point.hpp"
@ -24,6 +25,22 @@ class ConfigOption {
virtual void deserialize(std::string str) = 0; virtual void deserialize(std::string str) = 0;
}; };
template <class T>
class ConfigOptionVector
{
public:
virtual ~ConfigOptionVector() {};
std::vector<T> values;
T get_at(size_t i) {
try {
return this->values.at(i);
} catch (const std::out_of_range& oor) {
return this->values.front();
}
};
};
class ConfigOptionFloat : public ConfigOption class ConfigOptionFloat : public ConfigOption
{ {
public: public:
@ -43,10 +60,9 @@ class ConfigOptionFloat : public ConfigOption
}; };
}; };
class ConfigOptionFloats : public ConfigOption class ConfigOptionFloats : public ConfigOption, public ConfigOptionVector<double>
{ {
public: public:
std::vector<double> values;
std::string serialize() { std::string serialize() {
std::ostringstream ss; std::ostringstream ss;
@ -86,10 +102,9 @@ class ConfigOptionInt : public ConfigOption
}; };
}; };
class ConfigOptionInts : public ConfigOption class ConfigOptionInts : public ConfigOption, public ConfigOptionVector<int>
{ {
public: public:
std::vector<int> values;
std::string serialize() { std::string serialize() {
std::ostringstream ss; std::ostringstream ss;
@ -144,10 +159,9 @@ class ConfigOptionString : public ConfigOption
}; };
// semicolon-separated strings // semicolon-separated strings
class ConfigOptionStrings : public ConfigOption class ConfigOptionStrings : public ConfigOption, public ConfigOptionVector<std::string>
{ {
public: public:
std::vector<std::string> values;
std::string serialize() { std::string serialize() {
std::ostringstream ss; std::ostringstream ss;
@ -215,15 +229,14 @@ class ConfigOptionPoint : public ConfigOption
}; };
}; };
class ConfigOptionPoints : public ConfigOption class ConfigOptionPoints : public ConfigOption, public ConfigOptionVector<Pointf>
{ {
public: public:
Pointfs points;
std::string serialize() { std::string serialize() {
std::ostringstream ss; std::ostringstream ss;
for (Pointfs::const_iterator it = this->points.begin(); it != this->points.end(); ++it) { for (Pointfs::const_iterator it = this->values.begin(); it != this->values.end(); ++it) {
if (it - this->points.begin() != 0) ss << ","; if (it - this->values.begin() != 0) ss << ",";
ss << it->x; ss << it->x;
ss << "x"; ss << "x";
ss << it->y; ss << it->y;
@ -232,13 +245,13 @@ class ConfigOptionPoints : public ConfigOption
}; };
void deserialize(std::string str) { void deserialize(std::string str) {
this->points.clear(); this->values.clear();
std::istringstream is(str); std::istringstream is(str);
std::string point_str; std::string point_str;
while (std::getline(is, point_str, ',')) { while (std::getline(is, point_str, ',')) {
Pointf point; Pointf point;
sscanf(point_str.c_str(), "%lfx%lf", &point.x, &point.y); sscanf(point_str.c_str(), "%lfx%lf", &point.x, &point.y);
this->points.push_back(point); this->values.push_back(point);
} }
}; };
}; };
@ -260,10 +273,9 @@ class ConfigOptionBool : public ConfigOption
}; };
}; };
class ConfigOptionBools : public ConfigOption class ConfigOptionBools : public ConfigOption, public ConfigOptionVector<bool>
{ {
public: public:
std::vector<bool> values;
std::string serialize() { std::string serialize() {
std::ostringstream ss; std::ostringstream ss;
@ -398,6 +410,7 @@ class ConfigBase
#ifdef SLIC3RXS #ifdef SLIC3RXS
SV* as_hash(); SV* as_hash();
SV* get(t_config_option_key opt_key); SV* get(t_config_option_key opt_key);
SV* get_at(t_config_option_key opt_key, size_t i);
void set(t_config_option_key opt_key, SV* value); void set(t_config_option_key opt_key, SV* value);
#endif #endif
}; };

View File

@ -1131,8 +1131,8 @@ class PrintConfig : public virtual StaticConfig
this->external_perimeters_first.value = false; this->external_perimeters_first.value = false;
this->extruder_clearance_height.value = 20; this->extruder_clearance_height.value = 20;
this->extruder_clearance_radius.value = 20; this->extruder_clearance_radius.value = 20;
this->extruder_offset.points.resize(1); this->extruder_offset.values.resize(1);
this->extruder_offset.points[0] = Pointf(0,0); this->extruder_offset.values[0] = Pointf(0,0);
this->extrusion_axis.value = "E"; this->extrusion_axis.value = "E";
this->extrusion_multiplier.values.resize(1); this->extrusion_multiplier.values.resize(1);
this->extrusion_multiplier.values[0] = 1; this->extrusion_multiplier.values[0] = 1;

View File

@ -4,7 +4,7 @@ use strict;
use warnings; use warnings;
use Slic3r::XS; use Slic3r::XS;
use Test::More tests => 82; use Test::More tests => 88;
foreach my $config (Slic3r::Config->new, Slic3r::Config::Full->new) { foreach my $config (Slic3r::Config->new, Slic3r::Config::Full->new) {
$config->set('layer_height', 0.3); $config->set('layer_height', 0.3);
@ -75,6 +75,9 @@ foreach my $config (Slic3r::Config->new, Slic3r::Config::Full->new) {
$config->set('wipe', [1,0]); $config->set('wipe', [1,0]);
is_deeply $config->get('wipe'), [1,0], 'set/get bools'; is_deeply $config->get('wipe'), [1,0], 'set/get bools';
is $config->get_at('wipe', 0), 1, 'get_at bools';
is $config->get_at('wipe', 1), 0, 'get_at bools';
is $config->get_at('wipe', 9), 1, 'get_at bools';
is $config->serialize('wipe'), '1,0', 'serialize bools'; is $config->serialize('wipe'), '1,0', 'serialize bools';
$config->set_deserialize('wipe', '0,1,1'); $config->set_deserialize('wipe', '0,1,1');
is_deeply $config->get('wipe'), [0,1,1], 'deserialize bools'; is_deeply $config->get('wipe'), [0,1,1], 'deserialize bools';

View File

@ -11,6 +11,7 @@
bool has(t_config_option_key opt_key); bool has(t_config_option_key opt_key);
SV* as_hash(); SV* as_hash();
SV* get(t_config_option_key opt_key); SV* get(t_config_option_key opt_key);
SV* get_at(t_config_option_key opt_key, int i);
void set(t_config_option_key opt_key, SV* value); void set(t_config_option_key opt_key, SV* value);
void set_deserialize(t_config_option_key opt_key, std::string str); void set_deserialize(t_config_option_key opt_key, std::string str);
std::string serialize(t_config_option_key opt_key); std::string serialize(t_config_option_key opt_key);
@ -31,6 +32,7 @@
bool has(t_config_option_key opt_key); bool has(t_config_option_key opt_key);
SV* as_hash(); SV* as_hash();
SV* get(t_config_option_key opt_key); SV* get(t_config_option_key opt_key);
SV* get_at(t_config_option_key opt_key, int i);
void set(t_config_option_key opt_key, SV* value); void set(t_config_option_key opt_key, SV* value);
void set_deserialize(t_config_option_key opt_key, std::string str); void set_deserialize(t_config_option_key opt_key, std::string str);
std::string serialize(t_config_option_key opt_key); std::string serialize(t_config_option_key opt_key);
@ -50,6 +52,7 @@
bool has(t_config_option_key opt_key); bool has(t_config_option_key opt_key);
SV* as_hash(); SV* as_hash();
SV* get(t_config_option_key opt_key); SV* get(t_config_option_key opt_key);
SV* get_at(t_config_option_key opt_key, int i);
void set(t_config_option_key opt_key, SV* value); void set(t_config_option_key opt_key, SV* value);
void set_deserialize(t_config_option_key opt_key, std::string str); void set_deserialize(t_config_option_key opt_key, std::string str);
std::string serialize(t_config_option_key opt_key); std::string serialize(t_config_option_key opt_key);
@ -70,6 +73,7 @@
bool has(t_config_option_key opt_key); bool has(t_config_option_key opt_key);
SV* as_hash(); SV* as_hash();
SV* get(t_config_option_key opt_key); SV* get(t_config_option_key opt_key);
SV* get_at(t_config_option_key opt_key, int i);
void set(t_config_option_key opt_key, SV* value); void set(t_config_option_key opt_key, SV* value);
void set_deserialize(t_config_option_key opt_key, std::string str); void set_deserialize(t_config_option_key opt_key, std::string str);
std::string serialize(t_config_option_key opt_key); std::string serialize(t_config_option_key opt_key);
@ -90,6 +94,7 @@
bool has(t_config_option_key opt_key); bool has(t_config_option_key opt_key);
SV* as_hash(); SV* as_hash();
SV* get(t_config_option_key opt_key); SV* get(t_config_option_key opt_key);
SV* get_at(t_config_option_key opt_key, int i);
void set(t_config_option_key opt_key, SV* value); void set(t_config_option_key opt_key, SV* value);
void set_deserialize(t_config_option_key opt_key, std::string str); void set_deserialize(t_config_option_key opt_key, std::string str);
std::string serialize(t_config_option_key opt_key); std::string serialize(t_config_option_key opt_key);