mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-11-02 20:51:23 -07:00 
			
		
		
		
	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:
		
							parent
							
								
									ab9e3b718c
								
							
						
					
					
						commit
						bb9c3dd9ce
					
				
					 2 changed files with 40 additions and 13 deletions
				
			
		| 
						 | 
				
			
			@ -35,7 +35,7 @@ sub BUILD {
 | 
			
		|||
            $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;
 | 
			
		||||
        $self->_gcodegen($gcodegen);
 | 
			
		||||
        $gcodegen->set_placeholder_parser($self->placeholder_parser);
 | 
			
		||||
| 
						 | 
				
			
			@ -115,20 +115,21 @@ sub BUILD {
 | 
			
		|||
        if $self->config->pressure_advance > 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Export a G-code for the complete print.
 | 
			
		||||
sub export {
 | 
			
		||||
    my ($self) = @_;
 | 
			
		||||
    
 | 
			
		||||
    my $fh          = $self->fh;
 | 
			
		||||
    my $gcodegen    = $self->_gcodegen;
 | 
			
		||||
    
 | 
			
		||||
    # write some information
 | 
			
		||||
    # Write information on the generator.
 | 
			
		||||
    my @lt = localtime;
 | 
			
		||||
    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];
 | 
			
		||||
 | 
			
		||||
    # Write notes (content of the Print Settings tab -> Notes)
 | 
			
		||||
    print $fh "; $_\n" foreach split /\R/, $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 $layer_height = $first_object->config->layer_height;
 | 
			
		||||
    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
 | 
			
		||||
    $self->placeholder_parser->update_timestamp;
 | 
			
		||||
    
 | 
			
		||||
    # disable fan
 | 
			
		||||
    print $fh $gcodegen->writer->set_fan(0, 1)
 | 
			
		||||
        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 {
 | 
			
		||||
    my $self = shift;
 | 
			
		||||
    my ($layer, $object_copies) = @_;
 | 
			
		||||
| 
						 | 
				
			
			@ -484,7 +489,21 @@ sub process_layer {
 | 
			
		|||
        
 | 
			
		||||
        # group extrusions by extruder and then by island
 | 
			
		||||
        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)) {
 | 
			
		||||
            my $layerm = $layer->regions->[$region_id] or next;
 | 
			
		||||
            my $region = $self->print->get_region($region_id);
 | 
			
		||||
| 
						 | 
				
			
			@ -499,9 +518,12 @@ sub process_layer {
 | 
			
		|||
                    $by_extruder{$extruder_id} //= [];
 | 
			
		||||
                    
 | 
			
		||||
                    # $perimeter_coll is an ExtrusionPath::Collection object representing a single slice
 | 
			
		||||
                    for my $i (0 .. $#{$layer->slices}) {
 | 
			
		||||
                        if ($i == $#{$layer->slices}
 | 
			
		||||
                            || $layer->slices->[$i]->contour->contains_point($perimeter_coll->first_point)) {
 | 
			
		||||
                    for my $i (0 .. $n_slices) {
 | 
			
		||||
                        if (
 | 
			
		||||
                            # $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}{$region_id} //= [];
 | 
			
		||||
                            push @{ $by_extruder{$extruder_id}[$i]{perimeters}{$region_id} }, @$perimeter_coll;
 | 
			
		||||
| 
						 | 
				
			
			@ -527,9 +549,9 @@ sub process_layer {
 | 
			
		|||
                $by_extruder{$extruder_id} //= [];
 | 
			
		||||
                
 | 
			
		||||
                # $fill is an ExtrusionPath::Collection object
 | 
			
		||||
                for my $i (0 .. $#{$layer->slices}) {
 | 
			
		||||
                    if ($i == $#{$layer->slices}
 | 
			
		||||
                        || $layer->slices->[$i]->contour->contains_point($fill->first_point)) {
 | 
			
		||||
                for my $i (0 .. $n_slices) {
 | 
			
		||||
                    if ($i == $n_slices
 | 
			
		||||
                        || $point_inside_surface->($i, $fill->first_point)) {
 | 
			
		||||
                        $by_extruder{$extruder_id}[$i] //= { infill => {} };
 | 
			
		||||
                        $by_extruder{$extruder_id}[$i]{infill}{$region_id} //= [];
 | 
			
		||||
                        push @{ $by_extruder{$extruder_id}[$i]{infill}{$region_id} }, $fill;
 | 
			
		||||
| 
						 | 
				
			
			@ -583,6 +605,7 @@ sub process_layer {
 | 
			
		|||
    print {$self->fh} $self->filter($gcode);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Extrude perimeters: Decide where to put seams (hide or align seams).
 | 
			
		||||
sub _extrude_perimeters {
 | 
			
		||||
    my ($self, $entities_by_region) = @_;
 | 
			
		||||
    
 | 
			
		||||
| 
						 | 
				
			
			@ -595,6 +618,7 @@ sub _extrude_perimeters {
 | 
			
		|||
    return $gcode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Chain the paths hierarchically by a greedy algorithm to minimize a travel distance.
 | 
			
		||||
sub _extrude_infill {
 | 
			
		||||
    my ($self, $entities_by_region) = @_;
 | 
			
		||||
    
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -393,6 +393,10 @@ sub make_perimeters {
 | 
			
		|||
        for my $i (0 .. ($self->layer_count - 2)) {
 | 
			
		||||
            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_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 $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
 | 
			
		||||
                    my $intersection = intersection_ppl(
 | 
			
		||||
                        [ map $_->p, @{$upper_layerm->slices} ],
 | 
			
		||||
                        $upper_layerm_polygons,
 | 
			
		||||
                        $critical_area,
 | 
			
		||||
                    );
 | 
			
		||||
                    
 | 
			
		||||
                    # 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;
 | 
			
		||||
                    last unless $total_intersection_length > $total_loop_length*0.3;
 | 
			
		||||
                    
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue