Fix of git #3293: More efficient GCode export

This fixes two problems of repeatedly copying data from the C++ layer
to perl, by factoring the copying out of an inner loop.
This commit is contained in:
bubnikv 2016-06-01 20:58:05 +02:00
parent ab9e3b718c
commit bb9c3dd9ce
2 changed files with 40 additions and 13 deletions

View File

@ -35,7 +35,7 @@ sub BUILD {
$layer_count = sum(map { $_->total_layer_count } @{$self->objects}); $layer_count = sum(map { $_->total_layer_count } @{$self->objects});
} }
# set up our helper object # set up our helper object: This is a C++ Slic3r::GCode instance.
my $gcodegen = Slic3r::GCode->new; my $gcodegen = Slic3r::GCode->new;
$self->_gcodegen($gcodegen); $self->_gcodegen($gcodegen);
$gcodegen->set_placeholder_parser($self->placeholder_parser); $gcodegen->set_placeholder_parser($self->placeholder_parser);
@ -115,20 +115,21 @@ sub BUILD {
if $self->config->pressure_advance > 0; if $self->config->pressure_advance > 0;
} }
# Export a G-code for the complete print.
sub export { sub export {
my ($self) = @_; my ($self) = @_;
my $fh = $self->fh; my $fh = $self->fh;
my $gcodegen = $self->_gcodegen; my $gcodegen = $self->_gcodegen;
# write some information # Write information on the generator.
my @lt = localtime; my @lt = localtime;
printf $fh "; generated by Slic3r $Slic3r::VERSION on %04d-%02d-%02d at %02d:%02d:%02d\n\n", printf $fh "; generated by Slic3r $Slic3r::VERSION on %04d-%02d-%02d at %02d:%02d:%02d\n\n",
$lt[5] + 1900, $lt[4]+1, $lt[3], $lt[2], $lt[1], $lt[0]; $lt[5] + 1900, $lt[4]+1, $lt[3], $lt[2], $lt[1], $lt[0];
# Write notes (content of the Print Settings tab -> Notes)
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;
# Write some terse information on the slicing parameters.
my $first_object = $self->objects->[0]; my $first_object = $self->objects->[0];
my $layer_height = $first_object->config->layer_height; my $layer_height = $first_object->config->layer_height;
for my $region_id (0..$#{$self->print->regions}) { for my $region_id (0..$#{$self->print->regions}) {
@ -155,6 +156,7 @@ sub export {
# prepare the helper object for replacing placeholders in custom G-code and output filename # prepare the helper object for replacing placeholders in custom G-code and output filename
$self->placeholder_parser->update_timestamp; $self->placeholder_parser->update_timestamp;
# disable fan
print $fh $gcodegen->writer->set_fan(0, 1) print $fh $gcodegen->writer->set_fan(0, 1)
if $self->config->cooling && $self->config->disable_fan_first_layers; if $self->config->cooling && $self->config->disable_fan_first_layers;
@ -340,6 +342,9 @@ sub _print_first_layer_temperature {
} }
} }
# Called per object's layer.
# First a $gcode string is collected,
# then filtered and finally written to a file $fh.
sub process_layer { sub process_layer {
my $self = shift; my $self = shift;
my ($layer, $object_copies) = @_; my ($layer, $object_copies) = @_;
@ -484,7 +489,21 @@ sub process_layer {
# group extrusions by extruder and then by island # group extrusions by extruder and then by island
my %by_extruder = (); # extruder_id => [ { perimeters => \@perimeters, infill => \@infill } ] my %by_extruder = (); # extruder_id => [ { perimeters => \@perimeters, infill => \@infill } ]
my $n_slices = $#{$layer->slices};
my @layer_surface_bboxes = ();
for my $i (0 .. $n_slices) {
push @layer_surface_bboxes, $layer->slices->[$i]->contour->bounding_box;
}
my $point_inside_surface = sub {
my ($i, $point) = @_;
my $bbox = $layer_surface_bboxes[$i];
return
$point->x >= $bbox->x_min && $point->x < $bbox->x_max &&
$point->y >= $bbox->y_min && $point->y < $bbox->y_max &&
$layer->slices->[$i]->contour->contains_point($point);
};
foreach my $region_id (0..($self->print->region_count-1)) { foreach my $region_id (0..($self->print->region_count-1)) {
my $layerm = $layer->regions->[$region_id] or next; my $layerm = $layer->regions->[$region_id] or next;
my $region = $self->print->get_region($region_id); my $region = $self->print->get_region($region_id);
@ -499,9 +518,12 @@ sub process_layer {
$by_extruder{$extruder_id} //= []; $by_extruder{$extruder_id} //= [];
# $perimeter_coll is an ExtrusionPath::Collection object representing a single slice # $perimeter_coll is an ExtrusionPath::Collection object representing a single slice
for my $i (0 .. $#{$layer->slices}) { for my $i (0 .. $n_slices) {
if ($i == $#{$layer->slices} if (
|| $layer->slices->[$i]->contour->contains_point($perimeter_coll->first_point)) { # $perimeter_coll->first_point does not fit inside any slice
$i == $n_slices
# $perimeter_coll->first_point fits inside ith slice
|| $point_inside_surface->($i, $perimeter_coll->first_point)) {
$by_extruder{$extruder_id}[$i] //= { perimeters => {} }; $by_extruder{$extruder_id}[$i] //= { perimeters => {} };
$by_extruder{$extruder_id}[$i]{perimeters}{$region_id} //= []; $by_extruder{$extruder_id}[$i]{perimeters}{$region_id} //= [];
push @{ $by_extruder{$extruder_id}[$i]{perimeters}{$region_id} }, @$perimeter_coll; push @{ $by_extruder{$extruder_id}[$i]{perimeters}{$region_id} }, @$perimeter_coll;
@ -527,9 +549,9 @@ sub process_layer {
$by_extruder{$extruder_id} //= []; $by_extruder{$extruder_id} //= [];
# $fill is an ExtrusionPath::Collection object # $fill is an ExtrusionPath::Collection object
for my $i (0 .. $#{$layer->slices}) { for my $i (0 .. $n_slices) {
if ($i == $#{$layer->slices} if ($i == $n_slices
|| $layer->slices->[$i]->contour->contains_point($fill->first_point)) { || $point_inside_surface->($i, $fill->first_point)) {
$by_extruder{$extruder_id}[$i] //= { infill => {} }; $by_extruder{$extruder_id}[$i] //= { infill => {} };
$by_extruder{$extruder_id}[$i]{infill}{$region_id} //= []; $by_extruder{$extruder_id}[$i]{infill}{$region_id} //= [];
push @{ $by_extruder{$extruder_id}[$i]{infill}{$region_id} }, $fill; push @{ $by_extruder{$extruder_id}[$i]{infill}{$region_id} }, $fill;
@ -583,6 +605,7 @@ sub process_layer {
print {$self->fh} $self->filter($gcode); print {$self->fh} $self->filter($gcode);
} }
# Extrude perimeters: Decide where to put seams (hide or align seams).
sub _extrude_perimeters { sub _extrude_perimeters {
my ($self, $entities_by_region) = @_; my ($self, $entities_by_region) = @_;
@ -595,6 +618,7 @@ sub _extrude_perimeters {
return $gcode; return $gcode;
} }
# Chain the paths hierarchically by a greedy algorithm to minimize a travel distance.
sub _extrude_infill { sub _extrude_infill {
my ($self, $entities_by_region) = @_; my ($self, $entities_by_region) = @_;

View File

@ -393,6 +393,10 @@ sub make_perimeters {
for my $i (0 .. ($self->layer_count - 2)) { for my $i (0 .. ($self->layer_count - 2)) {
my $layerm = $self->get_layer($i)->get_region($region_id); my $layerm = $self->get_layer($i)->get_region($region_id);
my $upper_layerm = $self->get_layer($i+1)->get_region($region_id); my $upper_layerm = $self->get_layer($i+1)->get_region($region_id);
my $upper_layerm_polygons = [ map $_->p, @{$upper_layerm->slices} ];
# Filter upper layer polygons in intersection_ppl by their bounding boxes?
# my $upper_layerm_poly_bboxes= [ map $_->bounding_box, @{$upper_layerm_polygons} ];
my $total_loop_length = sum(map $_->length, @$upper_layerm_polygons) // 0;
my $perimeter_spacing = $layerm->flow(FLOW_ROLE_PERIMETER)->scaled_spacing; my $perimeter_spacing = $layerm->flow(FLOW_ROLE_PERIMETER)->scaled_spacing;
my $ext_perimeter_flow = $layerm->flow(FLOW_ROLE_EXTERNAL_PERIMETER); my $ext_perimeter_flow = $layerm->flow(FLOW_ROLE_EXTERNAL_PERIMETER);
@ -415,12 +419,11 @@ sub make_perimeters {
# check whether a portion of the upper slices falls inside the critical area # check whether a portion of the upper slices falls inside the critical area
my $intersection = intersection_ppl( my $intersection = intersection_ppl(
[ map $_->p, @{$upper_layerm->slices} ], $upper_layerm_polygons,
$critical_area, $critical_area,
); );
# only add an additional loop if at least 30% of the slice loop would benefit from it # only add an additional loop if at least 30% of the slice loop would benefit from it
my $total_loop_length = sum(map $_->length, map $_->p, @{$upper_layerm->slices}) // 0;
my $total_intersection_length = sum(map $_->length, @$intersection) // 0; my $total_intersection_length = sum(map $_->length, @$intersection) // 0;
last unless $total_intersection_length > $total_loop_length*0.3; last unless $total_intersection_length > $total_loop_length*0.3;