mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 20:21:12 -06:00 
			
		
		
		
	Refactoring: new Slic3r::Print::Simple class for non-interactive slicing (used in CLI and Quick Slice)
This commit is contained in:
		
							parent
							
								
									5bf0942f45
								
							
						
					
					
						commit
						385e0e0974
					
				
					 5 changed files with 151 additions and 88 deletions
				
			
		|  | @ -68,6 +68,7 @@ use Slic3r::Polyline; | ||||||
| use Slic3r::Print; | use Slic3r::Print; | ||||||
| use Slic3r::Print::Object; | use Slic3r::Print::Object; | ||||||
| use Slic3r::Print::Region; | use Slic3r::Print::Region; | ||||||
|  | use Slic3r::Print::Simple; | ||||||
| use Slic3r::Print::SupportMaterial; | use Slic3r::Print::SupportMaterial; | ||||||
| use Slic3r::Surface; | use Slic3r::Surface; | ||||||
| use Slic3r::TriangleMesh; | use Slic3r::TriangleMesh; | ||||||
|  |  | ||||||
|  | @ -88,25 +88,15 @@ sub quick_slice { | ||||||
|     my $self = shift; |     my $self = shift; | ||||||
|     my %params = @_; |     my %params = @_; | ||||||
|      |      | ||||||
|     my $process_dialog; |     my $progress_dialog; | ||||||
|     eval { |     eval { | ||||||
|         # validate configuration |         # validate configuration | ||||||
|         my $config = $self->config; |         my $config = $self->config; | ||||||
|         $config->validate; |         $config->validate; | ||||||
|          |          | ||||||
|         # confirm slicing of more than one copies |  | ||||||
|         my $copies = $config->duplicate_grid->[X] * $config->duplicate_grid->[Y]; |  | ||||||
|         $copies = $config->duplicate if $config->duplicate > 1; |  | ||||||
|         if ($copies > 1) { |  | ||||||
|             my $confirmation = Wx::MessageDialog->new($self, "Are you sure you want to slice $copies copies?", |  | ||||||
|                                                       'Multiple Copies', wxICON_QUESTION | wxOK | wxCANCEL); |  | ||||||
|             return unless $confirmation->ShowModal == wxID_OK; |  | ||||||
|         } |  | ||||||
|          |  | ||||||
|         # select input file |         # select input file | ||||||
|         my $dir = $Slic3r::GUI::Settings->{recent}{skein_directory} || $Slic3r::GUI::Settings->{recent}{config_directory} || ''; |  | ||||||
| 
 |  | ||||||
|         my $input_file; |         my $input_file; | ||||||
|  |         my $dir = $Slic3r::GUI::Settings->{recent}{skein_directory} || $Slic3r::GUI::Settings->{recent}{config_directory} || ''; | ||||||
|         if (!$params{reslice}) { |         if (!$params{reslice}) { | ||||||
|             my $dialog = Wx::FileDialog->new($self, 'Choose a file to slice (STL/OBJ/AMF):', $dir, "", MODEL_WILDCARD, wxFD_OPEN | wxFD_FILE_MUST_EXIST); |             my $dialog = Wx::FileDialog->new($self, 'Choose a file to slice (STL/OBJ/AMF):', $dir, "", MODEL_WILDCARD, wxFD_OPEN | wxFD_FILE_MUST_EXIST); | ||||||
|             if ($dialog->ShowModal != wxID_OK) { |             if ($dialog->ShowModal != wxID_OK) { | ||||||
|  | @ -133,31 +123,23 @@ sub quick_slice { | ||||||
|         $Slic3r::GUI::Settings->{recent}{skein_directory} = dirname($input_file); |         $Slic3r::GUI::Settings->{recent}{skein_directory} = dirname($input_file); | ||||||
|         Slic3r::GUI->save_settings; |         Slic3r::GUI->save_settings; | ||||||
|          |          | ||||||
|         my $print = $self->init_print; |         my $sprint = Slic3r::Print::Simple->new( | ||||||
|         my $model = eval { Slic3r::Model->read_from_file($input_file) }; |             status_cb       => sub { | ||||||
|         Slic3r::GUI::show_error($self, $@) if $@; |                 my ($percent, $message) = @_; | ||||||
|  |                 return if &Wx::wxVERSION_STRING !~ / 2\.(8\.|9\.[2-9])/; | ||||||
|  |                 $progress_dialog->Update($percent, "$message…"); | ||||||
|  |             }, | ||||||
|  |         ); | ||||||
|          |          | ||||||
|         if ($model->has_objects_with_no_instances) { |         $sprint->apply_config($config); | ||||||
|             # apply a default position to all objects not having one |         $sprint->set_model(Slic3r::Model->read_from_file($input_file)); | ||||||
|             foreach my $object (@{$model->objects}) { |  | ||||||
|                 $object->add_instance(offset => [0,0]) if !defined $object->instances; |  | ||||||
|             } |  | ||||||
|             $model->arrange_objects($config->min_object_distance); |  | ||||||
|         } |  | ||||||
|         $model->center_instances_around_point($config->print_center); |  | ||||||
|          |  | ||||||
|         foreach my $model_object (@{$model->objects}) { |  | ||||||
|             $print->auto_assign_extruders($model_object); |  | ||||||
|             $print->add_model_object($model_object); |  | ||||||
|         } |  | ||||||
|         $print->validate; |  | ||||||
|          |          | ||||||
|         # select output file |         # select output file | ||||||
|         my $output_file = $main::opt{output}; |         my $output_file; | ||||||
|         if ($params{reslice}) { |         if ($params{reslice}) { | ||||||
|             $output_file = $last_output_file if defined $last_output_file; |             $output_file = $last_output_file if defined $last_output_file; | ||||||
|         } elsif ($params{save_as}) { |         } elsif ($params{save_as}) { | ||||||
|             $output_file = $print->expanded_output_filepath($output_file); |             $output_file = $sprint->expanded_output_filepath; | ||||||
|             $output_file =~ s/\.gcode$/.svg/i if $params{export_svg}; |             $output_file =~ s/\.gcode$/.svg/i if $params{export_svg}; | ||||||
|             my $dlg = Wx::FileDialog->new($self, 'Save ' . ($params{export_svg} ? 'SVG' : 'G-code') . ' file as:', |             my $dlg = Wx::FileDialog->new($self, 'Save ' . ($params{export_svg} ? 'SVG' : 'G-code') . ' file as:', | ||||||
|                 Slic3r::GUI->output_path(dirname($output_file)), |                 Slic3r::GUI->output_path(dirname($output_file)), | ||||||
|  | @ -174,40 +156,32 @@ sub quick_slice { | ||||||
|         } |         } | ||||||
|          |          | ||||||
|         # show processbar dialog |         # show processbar dialog | ||||||
|         $process_dialog = Wx::ProgressDialog->new('Slicing…', "Processing $input_file_basename…",  |         $progress_dialog = Wx::ProgressDialog->new('Slicing…', "Processing $input_file_basename…",  | ||||||
|             100, $self, 0); |             100, $self, 0); | ||||||
|         $process_dialog->Pulse; |         $progress_dialog->Pulse; | ||||||
|          |          | ||||||
|         { |         { | ||||||
|             my @warnings = (); |             my @warnings = (); | ||||||
|             local $SIG{__WARN__} = sub { push @warnings, $_[0] }; |             local $SIG{__WARN__} = sub { push @warnings, $_[0] }; | ||||||
|             my %export_params = ( |              | ||||||
|                 output_file => $output_file, |             $sprint->output_file($output_file); | ||||||
|             ); |  | ||||||
|             $print->status_cb(sub { |  | ||||||
|                 my ($percent, $message) = @_; |  | ||||||
|                 if (&Wx::wxVERSION_STRING =~ / 2\.(8\.|9\.[2-9])/) { |  | ||||||
|                     $process_dialog->Update($percent, "$message…"); |  | ||||||
|                 } |  | ||||||
|             }); |  | ||||||
|             if ($params{export_svg}) { |             if ($params{export_svg}) { | ||||||
|                 $print->export_svg(%export_params); |                 $sprint->export_svg; | ||||||
|             } else { |             } else { | ||||||
|                 $print->process; |                 $sprint->export_gcode; | ||||||
|                 $print->export_gcode(%export_params); |  | ||||||
|             } |             } | ||||||
|             $print->status_cb(undef); |             $sprint->status_cb(undef); | ||||||
|             Slic3r::GUI::warning_catcher($self)->($_) for @warnings; |             Slic3r::GUI::warning_catcher($self)->($_) for @warnings; | ||||||
|         } |         } | ||||||
|         $process_dialog->Destroy; |         $progress_dialog->Destroy; | ||||||
|         undef $process_dialog; |         undef $progress_dialog; | ||||||
|          |          | ||||||
|         my $message = "$input_file_basename was successfully sliced."; |         my $message = "$input_file_basename was successfully sliced."; | ||||||
|         &Wx::wxTheApp->notify($message); |         &Wx::wxTheApp->notify($message); | ||||||
|         Wx::MessageDialog->new($self, $message, 'Slicing Done!',  |         Wx::MessageDialog->new($self, $message, 'Slicing Done!',  | ||||||
|             wxOK | wxICON_INFORMATION)->ShowModal; |             wxOK | wxICON_INFORMATION)->ShowModal; | ||||||
|     }; |     }; | ||||||
|     Slic3r::GUI::catch_error($self, sub { $process_dialog->Destroy if $process_dialog }); |     Slic3r::GUI::catch_error($self, sub { $progress_dialog->Destroy if $progress_dialog }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| sub repair_stl { | sub repair_stl { | ||||||
|  |  | ||||||
							
								
								
									
										112
									
								
								lib/Slic3r/Print/Simple.pm
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								lib/Slic3r/Print/Simple.pm
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,112 @@ | ||||||
|  | package Slic3r::Print::Simple; | ||||||
|  | use Moo; | ||||||
|  | 
 | ||||||
|  | use Slic3r::Geometry qw(X Y); | ||||||
|  | 
 | ||||||
|  | has '_print' => ( | ||||||
|  |     is      => 'ro', | ||||||
|  |     default => sub { Slic3r::Print->new }, | ||||||
|  |     handles => [qw(apply_config extruders expanded_output_filepath)], | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | has 'duplicate' => ( | ||||||
|  |     is      => 'rw', | ||||||
|  |     default => sub { 1 }, | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | has 'scale' => ( | ||||||
|  |     is      => 'rw', | ||||||
|  |     default => sub { 1 }, | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | has 'rotate' => ( | ||||||
|  |     is      => 'rw', | ||||||
|  |     default => sub { 0 }, | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | has 'duplicate_grid' => ( | ||||||
|  |     is      => 'rw', | ||||||
|  |     default => sub { [1,1] }, | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | has 'status_cb' => ( | ||||||
|  |     is      => 'rw', | ||||||
|  |     default => sub { sub {} }, | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | has 'output_file' => ( | ||||||
|  |     is      => 'rw', | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | sub set_model { | ||||||
|  |     my ($self, $model) = @_; | ||||||
|  |      | ||||||
|  |     # make method idempotent so that the object is reusable | ||||||
|  |     $self->_print->delete_all_objects; | ||||||
|  |      | ||||||
|  |     my $need_arrange = $model->has_objects_with_no_instances; | ||||||
|  |     if ($need_arrange) { | ||||||
|  |         # apply a default position to all objects not having one | ||||||
|  |         foreach my $object (@{$model->objects}) { | ||||||
|  |             $object->add_instance(offset => [0,0]) if !defined $object->instances; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     # apply scaling and rotation supplied from command line if any | ||||||
|  |     foreach my $instance (map @{$_->instances}, @{$model->objects}) { | ||||||
|  |         $instance->scaling_factor($instance->scaling_factor * $self->scale); | ||||||
|  |         $instance->rotation($instance->rotation + $self->rotate); | ||||||
|  |     } | ||||||
|  |     # TODO: --scale --rotate, --duplicate* shouldn't be stored in config | ||||||
|  |      | ||||||
|  |     if ($self->duplicate_grid->[X] > 1 || $self->duplicate_grid->[Y] > 1) { | ||||||
|  |         $model->duplicate_objects_grid($self->duplicate_grid, $self->_print->config->duplicate_distance); | ||||||
|  |     } elsif ($need_arrange) { | ||||||
|  |         $model->duplicate_objects($self->duplicate, $self->_print->config->min_object_distance); | ||||||
|  |     } elsif ($self->duplicate > 1) { | ||||||
|  |         # if all input objects have defined position(s) apply duplication to the whole model | ||||||
|  |         $model->duplicate($self->duplicate, $self->_print->config->min_object_distance); | ||||||
|  |     } | ||||||
|  |     $model->center_instances_around_point($self->_print->config->print_center); | ||||||
|  |      | ||||||
|  |     foreach my $model_object (@{$model->objects}) { | ||||||
|  |         $self->_print->auto_assign_extruders($model_object); | ||||||
|  |         $self->_print->add_model_object($model_object); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | sub _before_export { | ||||||
|  |     my ($self) = @_; | ||||||
|  |      | ||||||
|  |     $self->_print->status_cb($self->status_cb); | ||||||
|  |     $self->_print->validate; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | sub _after_export { | ||||||
|  |     my ($self) = @_; | ||||||
|  |      | ||||||
|  |     $self->_print->status_cb(undef); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | sub export_gcode { | ||||||
|  |     my ($self) = @_; | ||||||
|  |      | ||||||
|  |     $self->_before_export; | ||||||
|  |      | ||||||
|  |     $self->_print->process; | ||||||
|  |     $self->_print->export_gcode(output_file => $self->output_file); | ||||||
|  |      | ||||||
|  |     $self->_after_export; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | sub export_svg { | ||||||
|  |     my ($self) = @_; | ||||||
|  |      | ||||||
|  |     $self->_before_export; | ||||||
|  |      | ||||||
|  |     $self->_print->export_svg(output_file => $self->output_file); | ||||||
|  |      | ||||||
|  |     $self->_after_export; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 1; | ||||||
|  | @ -107,7 +107,7 @@ sub contact_area { | ||||||
|         } else { |         } else { | ||||||
|             my $lower_layer = $object->layers->[$layer_id-1]; |             my $lower_layer = $object->layers->[$layer_id-1]; | ||||||
|             foreach my $layerm (@{$layer->regions}) { |             foreach my $layerm (@{$layer->regions}) { | ||||||
|                 my $fw = $layerm->perimeter_flow->scaled_width; |                 my $fw = $layerm->flow(FLOW_ROLE_PERIMETER)->scaled_width; | ||||||
|                 my $diff; |                 my $diff; | ||||||
|              |              | ||||||
|                 # 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. | ||||||
|  |  | ||||||
							
								
								
									
										52
									
								
								slic3r.pl
									
										
									
									
									
								
							
							
						
						
									
										52
									
								
								slic3r.pl
									
										
									
									
									
								
							|  | @ -12,7 +12,6 @@ use Getopt::Long qw(:config no_auto_abbrev); | ||||||
| use List::Util qw(first); | use List::Util qw(first); | ||||||
| use POSIX qw(setlocale LC_NUMERIC); | use POSIX qw(setlocale LC_NUMERIC); | ||||||
| use Slic3r; | use Slic3r; | ||||||
| use Slic3r::Geometry qw(X Y); |  | ||||||
| use Time::HiRes qw(gettimeofday tv_interval); | use Time::HiRes qw(gettimeofday tv_interval); | ||||||
| $|++; | $|++; | ||||||
| 
 | 
 | ||||||
|  | @ -122,55 +121,32 @@ if (@ARGV) {  # slicing from command line | ||||||
|             $model = Slic3r::Model->read_from_file($input_file); |             $model = Slic3r::Model->read_from_file($input_file); | ||||||
|         } |         } | ||||||
|          |          | ||||||
|         my $need_arrange = $model->has_objects_with_no_instances; |  | ||||||
|         if ($need_arrange) { |  | ||||||
|             # apply a default position to all objects not having one |  | ||||||
|             foreach my $object (@{$model->objects}) { |  | ||||||
|                 $object->add_instance(offset => [0,0]) if !defined $object->instances; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|          |  | ||||||
|         # apply scaling and rotation supplied from command line if any |  | ||||||
|         foreach my $instance (map @{$_->instances}, @{$model->objects}) { |  | ||||||
|             $instance->scaling_factor($instance->scaling_factor * $config->scale); |  | ||||||
|             $instance->rotation($instance->rotation + $config->rotate); |  | ||||||
|         } |  | ||||||
|         # TODO: --scale --rotate, --duplicate* shouldn't be stored in config |  | ||||||
|          |  | ||||||
|         if ($config->duplicate_grid->[X] > 1 || $config->duplicate_grid->[Y] > 1) { |  | ||||||
|             $model->duplicate_objects_grid($config->duplicate_grid, $config->duplicate_distance); |  | ||||||
|         } elsif ($need_arrange) { |  | ||||||
|             $model->duplicate_objects($config->duplicate, $config->min_object_distance); |  | ||||||
|         } elsif ($config->duplicate > 1) { |  | ||||||
|             # if all input objects have defined position(s) apply duplication to the whole model |  | ||||||
|             $model->duplicate($config->duplicate, $config->min_object_distance); |  | ||||||
|         } |  | ||||||
|         $model->center_instances_around_point($config->print_center); |  | ||||||
|          |  | ||||||
|         if ($opt{info}) { |         if ($opt{info}) { | ||||||
|             $model->print_info; |             $model->print_info; | ||||||
|             next; |             next; | ||||||
|         } |         } | ||||||
|          |          | ||||||
|         my $print = Slic3r::Print->new( |         my $sprint = Slic3r::Print::Simple->new( | ||||||
|             status_cb   => sub { |             scale           => $config->scale, | ||||||
|  |             rotate          => $config->rotate, | ||||||
|  |             duplicate       => $config->duplicate, | ||||||
|  |             duplicate_grid  => $config->duplicate_grid, | ||||||
|  |             status_cb       => sub { | ||||||
|                 my ($percent, $message) = @_; |                 my ($percent, $message) = @_; | ||||||
|                 printf "=> %s\n", $message; |                 printf "=> %s\n", $message; | ||||||
|             }, |             }, | ||||||
|  |             output_file     => $opt{output}, | ||||||
|         ); |         ); | ||||||
|         $print->apply_config($config); |          | ||||||
|         foreach my $model_object (@{$model->objects}) { |         $sprint->apply_config($config); | ||||||
|             $print->auto_assign_extruders($model_object); |         $sprint->set_model($model); | ||||||
|             $print->add_model_object($model_object); |  | ||||||
|         } |  | ||||||
|         undef $model;  # free memory |         undef $model;  # free memory | ||||||
|         $print->validate; |          | ||||||
|         if ($opt{export_svg}) { |         if ($opt{export_svg}) { | ||||||
|             $print->export_svg(output_file => $opt{output}); |             $sprint->export_svg; | ||||||
|         } else { |         } else { | ||||||
|             my $t0 = [gettimeofday]; |             my $t0 = [gettimeofday]; | ||||||
|             $print->process; |             $sprint->export_gcode; | ||||||
|             $print->export_gcode(output_file => $opt{output}); |  | ||||||
|              |              | ||||||
|             # output some statistics |             # output some statistics | ||||||
|             { |             { | ||||||
|  | @ -180,7 +156,7 @@ if (@ARGV) {  # slicing from command line | ||||||
|             } |             } | ||||||
|             print map sprintf("Filament required: %.1fmm (%.1fcm3)\n", |             print map sprintf("Filament required: %.1fmm (%.1fcm3)\n", | ||||||
|                 $_->absolute_E, $_->extruded_volume/1000), |                 $_->absolute_E, $_->extruded_volume/1000), | ||||||
|                 @{$print->extruders}; |                 @{$sprint->extruders}; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } else { | } else { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Alessandro Ranellucci
						Alessandro Ranellucci