mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 12:11:15 -06:00 
			
		
		
		
	Refactoring: better API for Print/Object steps with explicit dependencies
This commit is contained in:
		
							parent
							
								
									d896ad090b
								
							
						
					
					
						commit
						4d76d05bbb
					
				
					 4 changed files with 182 additions and 160 deletions
				
			
		|  | @ -565,8 +565,9 @@ sub rotate { | |||
|         $_->set_rotation($new_angle) for @{ $model_object->instances }; | ||||
|         $model_object->update_bounding_box; | ||||
|          | ||||
|         # update print | ||||
|         # update print and start background processing | ||||
|         $self->{print}->add_model_object($model_object, $obj_idx); | ||||
|         $self->start_background_process; | ||||
|          | ||||
|         $object->transform_thumbnail($self->{model}, $obj_idx); | ||||
|     } | ||||
|  | @ -600,8 +601,9 @@ sub changescale { | |||
|         $_->set_scaling_factor($scale) for @{ $model_object->instances }; | ||||
|         $model_object->update_bounding_box; | ||||
|          | ||||
|         # update print | ||||
|         # update print and start background processing | ||||
|         $self->{print}->add_model_object($model_object, $obj_idx); | ||||
|         $self->start_background_process; | ||||
|          | ||||
|         $object->transform_thumbnail($self->{model}, $obj_idx); | ||||
|     } | ||||
|  |  | |||
|  | @ -219,9 +219,6 @@ sub add_model_object { | |||
|     # apply config to print object | ||||
|     $o->config->apply($self->default_object_config); | ||||
|     $o->config->apply_dynamic($object_config); | ||||
|      | ||||
|     $self->invalidate_step(STEP_SKIRT); | ||||
|     $self->invalidate_step(STEP_BRIM); | ||||
| } | ||||
| 
 | ||||
| sub reload_object { | ||||
|  | @ -328,12 +325,17 @@ sub extruders { | |||
| sub init_extruders { | ||||
|     my $self = shift; | ||||
|      | ||||
|     return if $self->step_done(STEP_INIT_EXTRUDERS); | ||||
|     $self->set_step_started(STEP_INIT_EXTRUDERS); | ||||
|      | ||||
|     # enforce tall skirt if using ooze_prevention | ||||
|     # FIXME: this is not idempotent (i.e. switching ooze_prevention off will not revert skirt settings) | ||||
|     if ($self->config->ooze_prevention && @{$self->extruders} > 1) { | ||||
|         $self->config->set('skirt_height', -1); | ||||
|         $self->config->set('skirts', 1) if $self->config->skirts == 0; | ||||
|     } | ||||
|      | ||||
|     $self->set_step_done(STEP_INIT_EXTRUDERS); | ||||
| } | ||||
| 
 | ||||
| # this value is not supposed to be compared with $layer->id | ||||
|  | @ -380,131 +382,11 @@ sub _simplify_slices { | |||
| sub process { | ||||
|     my ($self) = @_; | ||||
|      | ||||
|     my $status_cb = $self->status_cb // sub {}; | ||||
|      | ||||
|     my $print_step = sub { | ||||
|         my ($step, $cb) = @_; | ||||
|         if (!$self->step_done($step)) { | ||||
|             $self->set_step_started($step); | ||||
|             $cb->(); | ||||
|             $self->set_step_done($step); | ||||
|         } | ||||
|     }; | ||||
|     my $object_step = sub { | ||||
|         my ($step, $cb) = @_; | ||||
|         for my $obj_idx (0..($self->object_count - 1)) { | ||||
|             my $object = $self->objects->[$obj_idx]; | ||||
|             if (!$object->step_done($step)) { | ||||
|                 $object->set_step_started($step); | ||||
|                 $cb->($obj_idx); | ||||
|                 $object->set_step_done($step); | ||||
|             } | ||||
|         } | ||||
|     }; | ||||
|      | ||||
|     # STEP_INIT_EXTRUDERS | ||||
|     $print_step->(STEP_INIT_EXTRUDERS, sub { | ||||
|         $self->init_extruders; | ||||
|     }); | ||||
|      | ||||
|     # STEP_SLICE | ||||
|     # skein the STL into layers | ||||
|     # each layer has surfaces with holes | ||||
|     $status_cb->(10, "Processing triangulated mesh"); | ||||
|     $object_step->(STEP_SLICE, sub { | ||||
|         $self->objects->[$_[0]]->slice; | ||||
|     }); | ||||
|      | ||||
|     die "No layers were detected. You might want to repair your STL file(s) or check their size and retry.\n" | ||||
|         if !grep @{$_->layers}, @{$self->objects}; | ||||
|      | ||||
|     # make perimeters | ||||
|     # this will add a set of extrusion loops to each layer | ||||
|     # as well as generate infill boundaries | ||||
|     $status_cb->(20, "Generating perimeters"); | ||||
|     $object_step->(STEP_PERIMETERS, sub { | ||||
|         $self->objects->[$_[0]]->make_perimeters; | ||||
|     }); | ||||
|      | ||||
|     $status_cb->(30, "Preparing infill"); | ||||
|     $object_step->(STEP_PREPARE_INFILL, sub { | ||||
|         my $object = $self->objects->[$_[0]]; | ||||
|          | ||||
|         # this will assign a type (top/bottom/internal) to $layerm->slices | ||||
|         # and transform $layerm->fill_surfaces from expolygon  | ||||
|         # to typed top/bottom/internal surfaces; | ||||
|         $object->detect_surfaces_type; | ||||
|      | ||||
|         # decide what surfaces are to be filled | ||||
|         $_->prepare_fill_surfaces for map @{$_->regions}, @{$object->layers}; | ||||
|      | ||||
|         # this will detect bridges and reverse bridges | ||||
|         # and rearrange top/bottom/internal surfaces | ||||
|         $object->process_external_surfaces; | ||||
|      | ||||
|         # detect which fill surfaces are near external layers | ||||
|         # they will be split in internal and internal-solid surfaces | ||||
|         $object->discover_horizontal_shells; | ||||
|         $object->clip_fill_surfaces; | ||||
|          | ||||
|         # the following step needs to be done before combination because it may need | ||||
|         # to remove only half of the combined infill | ||||
|         $object->bridge_over_infill; | ||||
|      | ||||
|         # combine fill surfaces to honor the "infill every N layers" option | ||||
|         $object->combine_infill; | ||||
|     }); | ||||
|      | ||||
|     # this will generate extrusion paths for each layer | ||||
|     $status_cb->(70, "Infilling layers"); | ||||
|     $object_step->(STEP_INFILL, sub { | ||||
|         my $object = $self->objects->[$_[0]]; | ||||
|          | ||||
|         Slic3r::parallelize( | ||||
|             threads => $self->config->threads, | ||||
|             items => sub { | ||||
|                 my @items = ();  # [layer_id, region_id] | ||||
|                 for my $region_id (0 .. ($self->regions_count-1)) { | ||||
|                     push @items, map [$_, $region_id], 0..($object->layer_count - 1); | ||||
|                 } | ||||
|                 @items; | ||||
|             }, | ||||
|             thread_cb => sub { | ||||
|                 my $q = shift; | ||||
|                 while (defined (my $obj_layer = $q->dequeue)) { | ||||
|                     my ($i, $region_id) = @$obj_layer; | ||||
|                     my $layerm = $object->layers->[$i]->regions->[$region_id]; | ||||
|                     $layerm->fills->clear; | ||||
|                     $layerm->fills->append( $object->fill_maker->make_fill($layerm) ); | ||||
|                 } | ||||
|             }, | ||||
|             collect_cb => sub {}, | ||||
|             no_threads_cb => sub { | ||||
|                 foreach my $layerm (map @{$_->regions}, @{$object->layers}) { | ||||
|                     $layerm->fills->clear; | ||||
|                     $layerm->fills->append($object->fill_maker->make_fill($layerm)); | ||||
|                 } | ||||
|             }, | ||||
|         ); | ||||
|      | ||||
|         ### we could free memory now, but this would make this step not idempotent | ||||
|         ### $_->fill_surfaces->clear for map @{$_->regions}, @{$object->layers}; | ||||
|     }); | ||||
|      | ||||
|     # generate support material | ||||
|     $status_cb->(85, "Generating support material") if $self->has_support_material; | ||||
|     $object_step->(STEP_SUPPORTMATERIAL, sub { | ||||
|         $self->objects->[$_[0]]->generate_support_material; | ||||
|     }); | ||||
|      | ||||
|     # make skirt | ||||
|     $status_cb->(88, "Generating skirt/brim"); | ||||
|     $print_step->(STEP_SKIRT, sub { | ||||
|         $self->make_skirt; | ||||
|     }); | ||||
|     $print_step->(STEP_BRIM, sub { | ||||
|         $self->make_brim;  # must come after make_skirt | ||||
|     }); | ||||
|     $_->make_perimeters for @{$self->objects}; | ||||
|     $_->infill for @{$self->objects}; | ||||
|     $_->generate_support_material for @{$self->objects}; | ||||
|     $self->make_skirt; | ||||
|     $self->make_brim;  # must come after make_skirt | ||||
|      | ||||
|     # time to make some statistics | ||||
|     if (0) { | ||||
|  | @ -639,6 +521,15 @@ EOF | |||
| sub make_skirt { | ||||
|     my $self = shift; | ||||
|      | ||||
|     # prerequisites | ||||
|     $_->make_perimeters for @{$self->objects}; | ||||
|     $_->infill for @{$self->objects}; | ||||
|     $_->generate_support_material for @{$self->objects}; | ||||
|      | ||||
|     return if $self->step_done(STEP_SKIRT); | ||||
|     $self->set_step_started(STEP_SKIRT); | ||||
|     $self->status_cb->(88, "Generating skirt/brim"); | ||||
|      | ||||
|     # since this method must be idempotent, we clear skirt paths *before* | ||||
|     # checking whether we need to generate them | ||||
|     $self->skirt->clear; | ||||
|  | @ -749,11 +640,23 @@ sub make_skirt { | |||
|     } | ||||
|      | ||||
|     $self->skirt->reverse; | ||||
|      | ||||
|     $self->set_step_done(STEP_SKIRT); | ||||
| } | ||||
| 
 | ||||
| sub make_brim { | ||||
|     my $self = shift; | ||||
|      | ||||
|     # prerequisites | ||||
|     $_->make_perimeters for @{$self->objects}; | ||||
|     $_->infill for @{$self->objects}; | ||||
|     $_->generate_support_material for @{$self->objects}; | ||||
|     $self->make_skirt; | ||||
|      | ||||
|     return if $self->step_done(STEP_BRIM); | ||||
|     $self->set_step_started(STEP_BRIM); | ||||
|     $self->status_cb->(88, "Generating skirt/brim"); | ||||
|      | ||||
|     # since this method must be idempotent, we clear brim paths *before* | ||||
|     # checking whether we need to generate them | ||||
|     $self->brim->clear; | ||||
|  | @ -818,6 +721,8 @@ sub make_brim { | |||
|             height          => $first_layer_height, | ||||
|         ), | ||||
|     ), reverse @{union_pt_chained(\@loops)}); | ||||
|      | ||||
|     $self->set_step_done(STEP_BRIM); | ||||
| } | ||||
| 
 | ||||
| sub write_gcode { | ||||
|  |  | |||
|  | @ -97,7 +97,10 @@ sub bounding_box { | |||
| # this should be idempotent | ||||
| sub slice { | ||||
|     my $self = shift; | ||||
|     my %params = @_; | ||||
|      | ||||
|     return if $self->step_done(STEP_SLICE); | ||||
|     $self->set_step_started(STEP_SLICE); | ||||
|     $self->print->status_cb->(10, "Processing triangulated mesh"); | ||||
|      | ||||
|     # init layers | ||||
|     { | ||||
|  | @ -357,6 +360,11 @@ sub slice { | |||
|     if ($self->print->config->resolution) { | ||||
|         $self->_simplify_slices(scale($self->print->config->resolution)); | ||||
|     } | ||||
|      | ||||
|     die "No layers were detected. You might want to repair your STL file(s) or check their size and retry.\n" | ||||
|         if !@{$self->layers}; | ||||
|      | ||||
|     $self->set_step_done(STEP_SLICE); | ||||
| } | ||||
| 
 | ||||
| sub _slice_region { | ||||
|  | @ -394,6 +402,14 @@ sub _slice_region { | |||
| sub make_perimeters { | ||||
|     my $self = shift; | ||||
|      | ||||
|     # prerequisites | ||||
|     $self->print->init_extruders; | ||||
|     $self->slice; | ||||
|      | ||||
|     return if $self->step_done(STEP_PERIMETERS); | ||||
|     $self->set_step_started(STEP_PERIMETERS); | ||||
|     $self->print->status_cb->(20, "Generating perimeters"); | ||||
|      | ||||
|     # compare each layer to the one below, and mark those slices needing | ||||
|     # one additional inner perimeter, like the top of domed objects- | ||||
|      | ||||
|  | @ -473,6 +489,125 @@ sub make_perimeters { | |||
|     # we only need the max resolution for perimeters | ||||
|     ### This makes this method not-idempotent, so we keep it disabled for now. | ||||
|     ###$self->_simplify_slices(&Slic3r::SCALED_RESOLUTION); | ||||
|      | ||||
|     $self->set_step_done(STEP_PERIMETERS); | ||||
| } | ||||
| 
 | ||||
| sub prepare_infill { | ||||
|     my ($self) = @_; | ||||
|      | ||||
|     # prerequisites | ||||
|     $self->make_perimeters; | ||||
|      | ||||
|     return if $self->step_done(STEP_PREPARE_INFILL); | ||||
|     $self->set_step_started(STEP_PREPARE_INFILL); | ||||
|     $self->print->status_cb->(30, "Preparing infill"); | ||||
|      | ||||
|     # this will assign a type (top/bottom/internal) to $layerm->slices | ||||
|     # and transform $layerm->fill_surfaces from expolygon  | ||||
|     # to typed top/bottom/internal surfaces; | ||||
|     $self->detect_surfaces_type; | ||||
| 
 | ||||
|     # decide what surfaces are to be filled | ||||
|     $_->prepare_fill_surfaces for map @{$_->regions}, @{$self->layers}; | ||||
| 
 | ||||
|     # this will detect bridges and reverse bridges | ||||
|     # and rearrange top/bottom/internal surfaces | ||||
|     $self->process_external_surfaces; | ||||
| 
 | ||||
|     # detect which fill surfaces are near external layers | ||||
|     # they will be split in internal and internal-solid surfaces | ||||
|     $self->discover_horizontal_shells; | ||||
|     $self->clip_fill_surfaces; | ||||
|      | ||||
|     # the following step needs to be done before combination because it may need | ||||
|     # to remove only half of the combined infill | ||||
|     $self->bridge_over_infill; | ||||
| 
 | ||||
|     # combine fill surfaces to honor the "infill every N layers" option | ||||
|     $self->combine_infill; | ||||
|      | ||||
|     $self->set_step_done(STEP_PREPARE_INFILL); | ||||
| } | ||||
| 
 | ||||
| sub infill { | ||||
|     my ($self) = @_; | ||||
|      | ||||
|     # prerequisites | ||||
|     $self->prepare_infill; | ||||
|      | ||||
|     return if $self->step_done(STEP_INFILL); | ||||
|     $self->set_step_started(STEP_INFILL); | ||||
|     $self->print->status_cb->(70, "Infilling layers"); | ||||
|      | ||||
|     Slic3r::parallelize( | ||||
|         threads => $self->print->config->threads, | ||||
|         items => sub { | ||||
|             my @items = ();  # [layer_id, region_id] | ||||
|             for my $region_id (0 .. ($self->print->regions_count-1)) { | ||||
|                 push @items, map [$_, $region_id], 0..($self->layer_count - 1); | ||||
|             } | ||||
|             @items; | ||||
|         }, | ||||
|         thread_cb => sub { | ||||
|             my $q = shift; | ||||
|             while (defined (my $obj_layer = $q->dequeue)) { | ||||
|                 my ($i, $region_id) = @$obj_layer; | ||||
|                 my $layerm = $self->layers->[$i]->regions->[$region_id]; | ||||
|                 $layerm->fills->clear; | ||||
|                 $layerm->fills->append( $self->fill_maker->make_fill($layerm) ); | ||||
|             } | ||||
|         }, | ||||
|         collect_cb => sub {}, | ||||
|         no_threads_cb => sub { | ||||
|             foreach my $layerm (map @{$_->regions}, @{$self->layers}) { | ||||
|                 $layerm->fills->clear; | ||||
|                 $layerm->fills->append($self->fill_maker->make_fill($layerm)); | ||||
|             } | ||||
|         }, | ||||
|     ); | ||||
| 
 | ||||
|     ### we could free memory now, but this would make this step not idempotent | ||||
|     ### $_->fill_surfaces->clear for map @{$_->regions}, @{$object->layers}; | ||||
|      | ||||
|     $self->set_step_done(STEP_INFILL); | ||||
| } | ||||
| 
 | ||||
| sub generate_support_material { | ||||
|     my $self = shift; | ||||
|      | ||||
|     # prerequisites | ||||
|     $self->print->init_extruders; | ||||
|     $self->slice; | ||||
|      | ||||
|     return if $self->step_done(STEP_SUPPORTMATERIAL); | ||||
|     $self->set_step_started(STEP_SUPPORTMATERIAL); | ||||
|     $self->print->status_cb->(85, "Generating support material"); | ||||
|      | ||||
|     $self->clear_support_layers; | ||||
|      | ||||
|     return unless ($self->config->support_material || $self->config->raft_layers > 0) | ||||
|         && scalar(@{$self->layers}) >= 2; | ||||
|      | ||||
|     my $first_layer_flow = Slic3r::Flow->new_from_width( | ||||
|         width               => ($self->config->first_layer_extrusion_width || $self->config->support_material_extrusion_width), | ||||
|         role                => FLOW_ROLE_SUPPORT_MATERIAL, | ||||
|         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'), | ||||
|         bridge_flow_ratio   => 0, | ||||
|     ); | ||||
|      | ||||
|     my $s = Slic3r::Print::SupportMaterial->new( | ||||
|         print_config        => $self->print->config, | ||||
|         object_config       => $self->config, | ||||
|         first_layer_flow    => $first_layer_flow, | ||||
|         flow                => $self->support_material_flow, | ||||
|         interface_flow      => $self->support_material_flow(FLOW_ROLE_SUPPORT_MATERIAL_INTERFACE), | ||||
|     ); | ||||
|     $s->generate($self); | ||||
|      | ||||
|     $self->set_step_done(STEP_SUPPORTMATERIAL); | ||||
| } | ||||
| 
 | ||||
| sub detect_surfaces_type { | ||||
|  | @ -1005,33 +1140,6 @@ sub combine_infill { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| sub generate_support_material { | ||||
|     my $self = shift; | ||||
|      | ||||
|     $self->clear_support_layers; | ||||
|      | ||||
|     return unless ($self->config->support_material || $self->config->raft_layers > 0) | ||||
|         && scalar(@{$self->layers}) >= 2; | ||||
|      | ||||
|     my $first_layer_flow = Slic3r::Flow->new_from_width( | ||||
|         width               => ($self->config->first_layer_extrusion_width || $self->config->support_material_extrusion_width), | ||||
|         role                => FLOW_ROLE_SUPPORT_MATERIAL, | ||||
|         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'), | ||||
|         bridge_flow_ratio   => 0, | ||||
|     ); | ||||
|      | ||||
|     my $s = Slic3r::Print::SupportMaterial->new( | ||||
|         print_config        => $self->print->config, | ||||
|         object_config       => $self->config, | ||||
|         first_layer_flow    => $first_layer_flow, | ||||
|         flow                => $self->support_material_flow, | ||||
|         interface_flow      => $self->support_material_flow(FLOW_ROLE_SUPPORT_MATERIAL_INTERFACE), | ||||
|     ); | ||||
|     $s->generate($self); | ||||
| } | ||||
| 
 | ||||
| sub _simplify_slices { | ||||
|     my ($self, $distance) = @_; | ||||
|      | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Alessandro Ranellucci
						Alessandro Ranellucci