mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-31 12:41:20 -06:00 
			
		
		
		
	Refactoring: new Slic3r::Model class to represent files
This commit is contained in:
		
							parent
							
								
									c0322ec703
								
							
						
					
					
						commit
						f90520ed06
					
				
					 14 changed files with 255 additions and 88 deletions
				
			
		
							
								
								
									
										1
									
								
								MANIFEST
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								MANIFEST
									
										
									
									
									
								
							|  | @ -15,6 +15,7 @@ lib/Slic3r/Fill/Flowsnake.pm | ||||||
| lib/Slic3r/Fill/HilbertCurve.pm | lib/Slic3r/Fill/HilbertCurve.pm | ||||||
| lib/Slic3r/Fill/Honeycomb.pm | lib/Slic3r/Fill/Honeycomb.pm | ||||||
| lib/Slic3r/Fill/Line.pm | lib/Slic3r/Fill/Line.pm | ||||||
|  | lib/Slic3r/Fill/Model.pm | ||||||
| lib/Slic3r/Fill/OctagramSpiral.pm | lib/Slic3r/Fill/OctagramSpiral.pm | ||||||
| lib/Slic3r/Fill/PlanePath.pm | lib/Slic3r/Fill/PlanePath.pm | ||||||
| lib/Slic3r/Fill/Rectilinear.pm | lib/Slic3r/Fill/Rectilinear.pm | ||||||
|  |  | ||||||
|  | @ -41,6 +41,7 @@ use Slic3r::GCode; | ||||||
| use Slic3r::Geometry qw(PI); | use Slic3r::Geometry qw(PI); | ||||||
| use Slic3r::Layer; | use Slic3r::Layer; | ||||||
| use Slic3r::Line; | use Slic3r::Line; | ||||||
|  | use Slic3r::Model; | ||||||
| use Slic3r::Point; | use Slic3r::Point; | ||||||
| use Slic3r::Polygon; | use Slic3r::Polygon; | ||||||
| use Slic3r::Polyline; | use Slic3r::Polyline; | ||||||
|  |  | ||||||
|  | @ -25,15 +25,21 @@ sub read_file { | ||||||
|      |      | ||||||
|     close $fh; |     close $fh; | ||||||
|      |      | ||||||
|     $_ = Slic3r::TriangleMesh->new(vertices => $vertices, facets => $_) |     my $model = Slic3r::Model->new; | ||||||
|         for values %$meshes_by_material; |     my $object = $model->add_object(vertices => $vertices); | ||||||
|      |     foreach my $material (keys %$meshes_by_material) { | ||||||
|     return $materials, $meshes_by_material; |         push @{$model->materials}, $material;  # TODO: we should not add duplicate materials | ||||||
|  |         $object->add_volume( | ||||||
|  |             material_id => $#{$model->materials}, | ||||||
|  |             facets      => $meshes_by_material->{$material}, | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |     return $model; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| sub write_file { | sub write_file { | ||||||
|     my $self = shift; |     my $self = shift; | ||||||
|     my ($file, $materials, $meshes_by_material) = @_; |     my ($file, $model, %params) = @_; | ||||||
|      |      | ||||||
|     my %vertices_offset = (); |     my %vertices_offset = (); | ||||||
|      |      | ||||||
|  | @ -42,20 +48,20 @@ sub write_file { | ||||||
|     printf $fh qq{<?xml version="1.0" encoding="UTF-8"?>\n}; |     printf $fh qq{<?xml version="1.0" encoding="UTF-8"?>\n}; | ||||||
|     printf $fh qq{<amf unit="millimeter">\n}; |     printf $fh qq{<amf unit="millimeter">\n}; | ||||||
|     printf $fh qq{  <metadata type="cad">Slic3r %s</metadata>\n}, $Slic3r::VERSION; |     printf $fh qq{  <metadata type="cad">Slic3r %s</metadata>\n}, $Slic3r::VERSION; | ||||||
|     foreach my $material_id (keys %$materials) { |     for my $material_id (0 .. $#{ $model->materials }) { | ||||||
|         printf $fh qq{  <material id="%s">\n}, $material_id; |         my $material = $model->materials->[$material_id]; | ||||||
|         for (keys %{$materials->{$material_id}}) { |         printf $fh qq{  <material id="%d">\n}, $material_id; | ||||||
|              printf $fh qq{    <metadata type=\"%s\">%s</metadata>\n}, $_, $materials->{$material_id}{$_}; |         for (keys %$material) { | ||||||
|  |              printf $fh qq{    <metadata type=\"%s\">%s</metadata>\n}, $_, $material->{$_}; | ||||||
|         } |         } | ||||||
|         printf $fh qq{  </material>\n}; |         printf $fh qq{  </material>\n}; | ||||||
|     } |     } | ||||||
|     printf $fh qq{  <object id="0">\n}; |     for my $object_id (0 .. $#{ $model->objects }) { | ||||||
|  |         my $object = $model->objects->[$object_id]; | ||||||
|  |         printf $fh qq{  <object id="%d">\n}, $object_id; | ||||||
|         printf $fh qq{    <mesh>\n}; |         printf $fh qq{    <mesh>\n}; | ||||||
|         printf $fh qq{      <vertices>\n}; |         printf $fh qq{      <vertices>\n}; | ||||||
|     my $vertices_count = 0; |         foreach my $vertex (@{$object->vertices}, ) { | ||||||
|     foreach my $mesh (values %$meshes_by_material) { |  | ||||||
|         $vertices_offset{$mesh} = $vertices_count; |  | ||||||
|         foreach my $vertex (@{$mesh->vertices}, ) { |  | ||||||
|             printf $fh qq{        <vertex>\n}; |             printf $fh qq{        <vertex>\n}; | ||||||
|             printf $fh qq{          <coordinates>\n}; |             printf $fh qq{          <coordinates>\n}; | ||||||
|             printf $fh qq{            <x>%s</x>\n}, $vertex->[X]; |             printf $fh qq{            <x>%s</x>\n}, $vertex->[X]; | ||||||
|  | @ -63,24 +69,21 @@ sub write_file { | ||||||
|             printf $fh qq{            <z>%s</z>\n}, $vertex->[Z]; |             printf $fh qq{            <z>%s</z>\n}, $vertex->[Z]; | ||||||
|             printf $fh qq{          </coordinates>\n}; |             printf $fh qq{          </coordinates>\n}; | ||||||
|             printf $fh qq{        </vertex>\n}; |             printf $fh qq{        </vertex>\n}; | ||||||
|             $vertices_count++; |  | ||||||
|         } |  | ||||||
|         } |         } | ||||||
|         printf $fh qq{      </vertices>\n}; |         printf $fh qq{      </vertices>\n}; | ||||||
|     foreach my $material_id (sort keys %$meshes_by_material) { |         foreach my $volume (@{ $object->volumes }) { | ||||||
|         my $mesh = $meshes_by_material->{$material_id}; |  | ||||||
|             printf $fh qq{      <volume%s>\n}, |             printf $fh qq{      <volume%s>\n}, | ||||||
|             ($material_id eq '_') ? '' : " materialid=\"$material_id\""; |                 (!defined $volume->material_id) ? '' : (sprintf ' materialid="%s"', $volume->material_id); | ||||||
|         foreach my $facet (@{$mesh->facets}) { |             foreach my $facet (@{$volume->facets}) { | ||||||
|                 printf $fh qq{        <triangle>\n}; |                 printf $fh qq{        <triangle>\n}; | ||||||
|             printf $fh qq{          <v%d>%d</v%d>\n}, $_, $facet->[$_] + $vertices_offset{$mesh}, $_ |                 printf $fh qq{          <v%d>%d</v%d>\n}, $_, $facet->[$_], $_ for -3..-1; | ||||||
|                 for -3..-1; |  | ||||||
|                 printf $fh qq{        </triangle>\n}; |                 printf $fh qq{        </triangle>\n}; | ||||||
|             } |             } | ||||||
|             printf $fh qq{      </volume>\n}; |             printf $fh qq{      </volume>\n}; | ||||||
|         } |         } | ||||||
|         printf $fh qq{    </mesh>\n}; |         printf $fh qq{    </mesh>\n}; | ||||||
|         printf $fh qq{  </object>\n}; |         printf $fh qq{  </object>\n}; | ||||||
|  |     } | ||||||
|     printf $fh qq{</amf>\n}; |     printf $fh qq{</amf>\n}; | ||||||
|     close $fh; |     close $fh; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -71,7 +71,7 @@ sub end_element { | ||||||
|     } elsif ($data->{LocalName} eq 'triangle') { |     } elsif ($data->{LocalName} eq 'triangle') { | ||||||
|         push @{$self->{_volume}}, $self->{_triangle}; |         push @{$self->{_volume}}, $self->{_triangle}; | ||||||
|         $self->{_triangle} = undef; |         $self->{_triangle} = undef; | ||||||
|     } elsif ($self->{_vertex_idx} && $data->{LocalName} =~ /^v[123]$/) { |     } elsif (defined $self->{_vertex_idx} && $data->{LocalName} =~ /^v[123]$/) { | ||||||
|         $self->{_vertex_idx} = undef; |         $self->{_vertex_idx} = undef; | ||||||
|     } elsif ($data->{LocalName} eq 'material') { |     } elsif ($data->{LocalName} eq 'material') { | ||||||
|         $self->{_materials}{ $self->{_material_id} } = $self->{_material}; |         $self->{_materials}{ $self->{_material_id} } = $self->{_material}; | ||||||
|  |  | ||||||
|  | @ -17,7 +17,10 @@ sub read_file { | ||||||
|     } |     } | ||||||
|     close $fh; |     close $fh; | ||||||
|      |      | ||||||
|     return Slic3r::TriangleMesh->new(vertices => $vertices, facets => $facets); |     my $model = Slic3r::Model->new; | ||||||
|  |     my $object = $model->add_object(vertices => $vertices); | ||||||
|  |     my $volume = $object->add_volume(facets => $facets); | ||||||
|  |     return $model; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 1; | 1; | ||||||
|  |  | ||||||
|  | @ -117,7 +117,10 @@ sub read_file { | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     return Slic3r::TriangleMesh->new(vertices => $vertices, facets => $facets); |     my $model = Slic3r::Model->new; | ||||||
|  |     my $object = $model->add_object(vertices => $vertices); | ||||||
|  |     my $volume = $object->add_volume(facets => $facets); | ||||||
|  |     return $model; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| sub _read_ascii { | sub _read_ascii { | ||||||
|  | @ -161,13 +164,13 @@ sub _read_binary { | ||||||
| 
 | 
 | ||||||
| sub write_file { | sub write_file { | ||||||
|     my $self = shift; |     my $self = shift; | ||||||
|     my ($file, $mesh, $binary) = @_; |     my ($file, $model, %params) = @_; | ||||||
|      |      | ||||||
|     open my $fh, '>', $file; |     open my $fh, '>', $file; | ||||||
|      |      | ||||||
|     $binary |     $params{binary} | ||||||
|         ? _write_binary($fh, $mesh) |         ? _write_binary($fh, $model->mesh) | ||||||
|         : _write_ascii($fh, $mesh); |         : _write_ascii($fh, $model->mesh); | ||||||
|      |      | ||||||
|     close $fh; |     close $fh; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -296,7 +296,7 @@ sub load_file { | ||||||
|     my $process_dialog = Wx::ProgressDialog->new('Loading…', "Processing input file…", 100, $self, 0); |     my $process_dialog = Wx::ProgressDialog->new('Loading…', "Processing input file…", 100, $self, 0); | ||||||
|     $process_dialog->Pulse; |     $process_dialog->Pulse; | ||||||
|     local $SIG{__WARN__} = Slic3r::GUI::warning_catcher($self); |     local $SIG{__WARN__} = Slic3r::GUI::warning_catcher($self); | ||||||
|     $self->{print}->add_object_from_file($input_file); |     $self->{print}->add_objects_from_file($input_file); | ||||||
|     my $obj_idx = $#{$self->{print}->objects}; |     my $obj_idx = $#{$self->{print}->objects}; | ||||||
|     $process_dialog->Destroy; |     $process_dialog->Destroy; | ||||||
|      |      | ||||||
|  | @ -631,12 +631,10 @@ sub on_export_failed { | ||||||
| sub export_stl { | sub export_stl { | ||||||
|     my $self = shift; |     my $self = shift; | ||||||
|          |          | ||||||
|     my $print = $self->{print}; |  | ||||||
|          |  | ||||||
|     # select output file |     # select output file | ||||||
|     my $output_file = $main::opt{output}; |     my $output_file = $main::opt{output}; | ||||||
|     { |     { | ||||||
|         $output_file = $print->expanded_output_filepath($output_file); |         $output_file = $self->{print}->expanded_output_filepath($output_file); | ||||||
|         $output_file =~ s/\.gcode$/.stl/i; |         $output_file =~ s/\.gcode$/.stl/i; | ||||||
|         my $dlg = Wx::FileDialog->new($self, 'Save STL file as:', dirname($output_file), |         my $dlg = Wx::FileDialog->new($self, 'Save STL file as:', dirname($output_file), | ||||||
|             basename($output_file), $Slic3r::GUI::SkeinPanel::model_wildcard, wxFD_SAVE | wxFD_OVERWRITE_PROMPT); |             basename($output_file), $Slic3r::GUI::SkeinPanel::model_wildcard, wxFD_SAVE | wxFD_OVERWRITE_PROMPT); | ||||||
|  | @ -648,23 +646,28 @@ sub export_stl { | ||||||
|         $dlg->Destroy; |         $dlg->Destroy; | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     my $mesh = Slic3r::TriangleMesh->new(facets => [], vertices => []); |     Slic3r::Format::STL->write_file($output_file, $self->make_model, binary => 1); | ||||||
|     for my $obj_idx (0 .. $#{$print->objects}) { |  | ||||||
|         for my $copy (@{$print->copies->[$obj_idx]}) { |  | ||||||
|             my $cloned_mesh = $print->objects->[$obj_idx]->mesh->clone; |  | ||||||
|             $cloned_mesh->move(@$copy); |  | ||||||
|             my $vertices_offset = scalar @{$mesh->vertices}; |  | ||||||
|             push @{$mesh->vertices}, @{$cloned_mesh->vertices}; |  | ||||||
|             push @{$mesh->facets}, map [ $_->[0], map $vertices_offset + $_, @$_[-3..-1] ], @{$cloned_mesh->facets}; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     $mesh->scale(&Slic3r::SCALING_FACTOR); |  | ||||||
|     $mesh->align_to_origin; |  | ||||||
|      |  | ||||||
|     Slic3r::Format::STL->write_file($output_file, $mesh, 1); |  | ||||||
|     $self->statusbar->SetStatusText("STL file exported to $output_file"); |     $self->statusbar->SetStatusText("STL file exported to $output_file"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | sub make_model { | ||||||
|  |     my $self = shift; | ||||||
|  |      | ||||||
|  |     my $model = Slic3r::Model->new; | ||||||
|  |     for my $obj_idx (0 .. $#{$self->{print}->objects}) { | ||||||
|  |         my $mesh = $self->{print}->objects->[$obj_idx]->mesh->clone; | ||||||
|  |         $mesh->scale(&Slic3r::SCALING_FACTOR); | ||||||
|  |         my $object = $model->add_object(vertices => $mesh->vertices); | ||||||
|  |         $object->add_volume(facets => $mesh->facets); | ||||||
|  |         for my $copy (@{$self->{print}->copies->[$obj_idx]}) { | ||||||
|  |             $object->add_instance(rotation => 0, offset => [ map unscale $_, @$copy ]); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     # TODO: $model->align_to_origin; | ||||||
|  |      | ||||||
|  |     return $model; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| sub make_thumbnail { | sub make_thumbnail { | ||||||
|     my $self = shift; |     my $self = shift; | ||||||
|     my ($obj_idx) = @_; |     my ($obj_idx) = @_; | ||||||
|  |  | ||||||
|  | @ -96,7 +96,7 @@ sub do_slice { | ||||||
|         Slic3r::GUI->save_settings; |         Slic3r::GUI->save_settings; | ||||||
|          |          | ||||||
|         my $print = Slic3r::Print->new(config => $config); |         my $print = Slic3r::Print->new(config => $config); | ||||||
|         $print->add_object_from_file($input_file); |         $print->add_objects_from_file($input_file); | ||||||
|         $print->validate; |         $print->validate; | ||||||
| 
 | 
 | ||||||
|         # select output file |         # select output file | ||||||
|  |  | ||||||
							
								
								
									
										112
									
								
								lib/Slic3r/Model.pm
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								lib/Slic3r/Model.pm
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,112 @@ | ||||||
|  | package Slic3r::Model; | ||||||
|  | use Moo; | ||||||
|  | 
 | ||||||
|  | use Slic3r::Geometry qw(X Y Z); | ||||||
|  | 
 | ||||||
|  | has 'materials' => (is => 'ro', default => sub { [] }); | ||||||
|  | has 'objects'   => (is => 'ro', default => sub { [] }); | ||||||
|  | 
 | ||||||
|  | sub add_object { | ||||||
|  |     my $self = shift; | ||||||
|  |      | ||||||
|  |     my $object = Slic3r::Model::Object->new(model => $self, @_); | ||||||
|  |     push @{$self->objects}, $object; | ||||||
|  |     return $object; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # flattens everything to a single mesh | ||||||
|  | sub mesh { | ||||||
|  |     my $self = shift; | ||||||
|  |      | ||||||
|  |     my $vertices = []; | ||||||
|  |     my $facets = []; | ||||||
|  |     foreach my $object (@{$self->objects}) { | ||||||
|  |         my @instances = $object->instances ? @{$object->instances} : (undef); | ||||||
|  |         foreach my $instance (@instances) { | ||||||
|  |             my @vertices = @{$object->vertices}; | ||||||
|  |             if ($instance) { | ||||||
|  |                 # save Z coordinates, as rotation and translation discard them | ||||||
|  |                 my @z = map $_->[Z], @vertices; | ||||||
|  |                  | ||||||
|  |                 if ($instance->rotation) { | ||||||
|  |                     # transform vertex coordinates | ||||||
|  |                     my $rad = Slic3r::Geometry::deg2rad($instance->rotation); | ||||||
|  |                     @vertices = Slic3r::Geometry::rotate_points($rad, undef, @vertices); | ||||||
|  |                 } | ||||||
|  |                 @vertices = Slic3r::Geometry::move_points($instance->offset, @vertices); | ||||||
|  |                  | ||||||
|  |                 # reapply Z coordinates | ||||||
|  |                 $vertices[$_][Z] = $z[$_] for 0 .. $#z; | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             my $v_offset = @$vertices; | ||||||
|  |             push @$vertices, @vertices; | ||||||
|  |             foreach my $volume (@{$object->volumes}) { | ||||||
|  |                 push @$facets, map { | ||||||
|  |                     my $f = [@$_]; | ||||||
|  |                     $f->[$_] += $v_offset for -3..-1; | ||||||
|  |                     $f; | ||||||
|  |                 } @{$volume->facets}; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     return Slic3r::TriangleMesh->new( | ||||||
|  |         vertices => $vertices, | ||||||
|  |         facets   => $facets, | ||||||
|  |     ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | package Slic3r::Model::Material; | ||||||
|  | use Moo; | ||||||
|  | 
 | ||||||
|  | has 'model'         => (is => 'ro', weak_ref => 1, required => 1); | ||||||
|  | has 'attributes'    => (is => 'rw', default => sub { {} }); | ||||||
|  | 
 | ||||||
|  | package Slic3r::Model::Object; | ||||||
|  | use Moo; | ||||||
|  | 
 | ||||||
|  | has 'model'     => (is => 'ro', weak_ref => 1, required => 1); | ||||||
|  | has 'vertices'  => (is => 'ro', default => sub { [] }); | ||||||
|  | has 'volumes'   => (is => 'ro', default => sub { [] }); | ||||||
|  | has 'instances' => (is => 'rw'); | ||||||
|  | 
 | ||||||
|  | sub add_volume { | ||||||
|  |     my $self = shift; | ||||||
|  |      | ||||||
|  |     my $volume = Slic3r::Model::Volume->new(object => $self, @_); | ||||||
|  |     push @{$self->volumes}, $volume; | ||||||
|  |     return $volume; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | sub add_instance { | ||||||
|  |     my $self = shift; | ||||||
|  |      | ||||||
|  |     $self->instances([]) if !defined $self->instances; | ||||||
|  |     push @{$self->instances}, Slic3r::Model::Instance->new(object => $self, @_); | ||||||
|  |     return $self->instances->[-1]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | package Slic3r::Model::Volume; | ||||||
|  | use Moo; | ||||||
|  | 
 | ||||||
|  | has 'object'        => (is => 'ro', weak_ref => 1, required => 1); | ||||||
|  | has 'material_id'   => (is => 'rw'); | ||||||
|  | has 'facets'        => (is => 'rw', default => sub { [] }); | ||||||
|  | 
 | ||||||
|  | sub mesh { | ||||||
|  |     my $self = shift; | ||||||
|  |     return Slic3r::TriangleMesh->new( | ||||||
|  |         vertices => $self->object->vertices, | ||||||
|  |         facets   => $self->facets, | ||||||
|  |     ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | package Slic3r::Model::Instance; | ||||||
|  | use Moo; | ||||||
|  | 
 | ||||||
|  | has 'object'    => (is => 'ro', weak_ref => 1, required => 1); | ||||||
|  | has 'rotation'  => (is => 'rw', default => sub { 0 }); | ||||||
|  | has 'offset'    => (is => 'rw'); | ||||||
|  | 
 | ||||||
|  | 1; | ||||||
|  | @ -79,28 +79,43 @@ sub _trigger_config { | ||||||
|     $self->config->set_ifndef('top_solid_infill_speed', $self->config->solid_infill_speed); |     $self->config->set_ifndef('top_solid_infill_speed', $self->config->solid_infill_speed); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| sub add_object_from_file { | sub add_objects_from_file { | ||||||
|     my $self = shift; |     my $self = shift; | ||||||
|     my ($input_file) = @_; |     my ($input_file) = @_; | ||||||
|      |      | ||||||
|     my $object; |     my $model = $input_file =~ /\.stl$/i            ? Slic3r::Format::STL->read_file($input_file) | ||||||
|     if ($input_file =~ /\.stl$/i) { |               : $input_file =~ /\.obj$/i            ? Slic3r::Format::OBJ->read_file($input_file) | ||||||
|         my $mesh = Slic3r::Format::STL->read_file($input_file); |               : $input_file =~ /\.amf(\.xml)?$/i    ? Slic3r::Format::AMF->read_file($input_file) | ||||||
|  |               : die "Input file must have .stl, .obj or .amf(.xml) extension\n"; | ||||||
|  |      | ||||||
|  |     my @print_objects = $self->add_model($model); | ||||||
|  |     $_->input_file($input_file) for @print_objects; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | sub add_model { | ||||||
|  |     my $self = shift; | ||||||
|  |     my ($model) = @_; | ||||||
|  |      | ||||||
|  |     my @print_objects = (); | ||||||
|  |     foreach my $object (@{ $model->objects }) { | ||||||
|  |         my $mesh = $object->volumes->[0]->mesh; | ||||||
|         $mesh->check_manifoldness; |         $mesh->check_manifoldness; | ||||||
|         $object = $self->add_object_from_mesh($mesh); |          | ||||||
|     } elsif ($input_file =~ /\.obj$/i) { |         if ($object->instances) { | ||||||
|         my $mesh = Slic3r::Format::OBJ->read_file($input_file); |             # we ignore the per-instance rotation currently and only  | ||||||
|         $mesh->check_manifoldness; |             # consider the first one | ||||||
|         $object = $self->add_object_from_mesh($mesh); |             $mesh->rotate($object->instances->[0]->rotation); | ||||||
|     } elsif ( $input_file =~ /\.amf(\.xml)?$/i) { |  | ||||||
|         my ($materials, $meshes_by_material) = Slic3r::Format::AMF->read_file($input_file); |  | ||||||
|         $_->check_manifoldness for values %$meshes_by_material; |  | ||||||
|         $object = $self->add_object_from_mesh($meshes_by_material->{_} || +(values %$meshes_by_material)[0]); |  | ||||||
|     } else { |  | ||||||
|         die "Input file must have .stl, .obj or .amf(.xml) extension\n"; |  | ||||||
|         } |         } | ||||||
|     $object->input_file($input_file); |          | ||||||
|     return $object; |         push @print_objects, $self->add_object_from_mesh($mesh); | ||||||
|  |          | ||||||
|  |         if ($object->instances) { | ||||||
|  |             # replace the default [0,0] instance with the custom ones | ||||||
|  |             @{$self->copies->[-1]} = map [ scale $_->offset->[X], scale $_->offset->[X] ], @{$object->instances}; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     return @print_objects; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| sub add_object_from_mesh { | sub add_object_from_mesh { | ||||||
|  |  | ||||||
|  | @ -88,9 +88,9 @@ if (@ARGV) {  # slicing from command line | ||||||
|      |      | ||||||
|     while (my $input_file = shift @ARGV) { |     while (my $input_file = shift @ARGV) { | ||||||
|         my $print = Slic3r::Print->new(config => $config); |         my $print = Slic3r::Print->new(config => $config); | ||||||
|         $print->add_object_from_file($input_file); |         $print->add_objects_from_file($input_file); | ||||||
|         if ($opt{merge}) { |         if ($opt{merge}) { | ||||||
|             $print->add_object_from_file($_) for splice @ARGV, 0; |             $print->add_objects_from_file($_) for splice @ARGV, 0; | ||||||
|         } |         } | ||||||
|         $print->duplicate; |         $print->duplicate; | ||||||
|         $print->arrange_objects if @{$print->objects} > 1; |         $print->arrange_objects if @{$print->objects} > 1; | ||||||
|  |  | ||||||
|  | @ -25,12 +25,12 @@ my %opt = (); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| { | { | ||||||
|     my $mesh = Slic3r::Format::AMF->read_file($ARGV[0]); |     my $model = Slic3r::Format::AMF->read_file($ARGV[0]); | ||||||
|     my $output_file = $ARGV[0]; |     my $output_file = $ARGV[0]; | ||||||
|     $output_file =~ s/\.amf(?:\.xml)?$/\.stl/i; |     $output_file =~ s/\.amf(?:\.xml)?$/\.stl/i; | ||||||
|      |      | ||||||
|     printf "Writing to %s\n", basename($output_file); |     printf "Writing to %s\n", basename($output_file); | ||||||
|     Slic3r::Format::STL->write_file($output_file, $mesh, !$opt{ascii}); |     Slic3r::Format::STL->write_file($output_file, $model, binary => !$opt{ascii}); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -25,15 +25,20 @@ my %opt = (); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| { | { | ||||||
|     my $mesh = Slic3r::Format::STL->read_file($ARGV[0]); |     my $model = Slic3r::Format::STL->read_file($ARGV[0]); | ||||||
|     my $basename = $ARGV[0]; |     my $basename = $ARGV[0]; | ||||||
|     $basename =~ s/\.stl$//i; |     $basename =~ s/\.stl$//i; | ||||||
|      |      | ||||||
|     my $part_count = 0; |     my $part_count = 0; | ||||||
|     foreach my $new_mesh ($mesh->split_mesh) { |     foreach my $new_mesh ($model->mesh->split_mesh) { | ||||||
|  |         my $new_model = Slic3r::Model->new; | ||||||
|  |         $new_model | ||||||
|  |             ->add_object(vertices   => $new_mesh->vertices) | ||||||
|  |             ->add_volume(facets     => $new_mesh->facets); | ||||||
|  |          | ||||||
|         my $output_file = sprintf '%s_%02d.stl', $basename, ++$part_count; |         my $output_file = sprintf '%s_%02d.stl', $basename, ++$part_count; | ||||||
|         printf "Writing to %s\n", basename($output_file); |         printf "Writing to %s\n", basename($output_file); | ||||||
|         Slic3r::Format::STL->write_file($output_file, $new_mesh, !$opt{ascii}); |         Slic3r::Format::STL->write_file($output_file, $new_model, binary => !$opt{ascii}); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -18,29 +18,49 @@ my %opt = (); | ||||||
| { | { | ||||||
|     my %options = ( |     my %options = ( | ||||||
|         'help'                  => sub { usage() }, |         'help'                  => sub { usage() }, | ||||||
|  |         'distinct-materials'    => \$opt{distinct_materials}, | ||||||
|     ); |     ); | ||||||
|     GetOptions(%options) or usage(1); |     GetOptions(%options) or usage(1); | ||||||
|     $ARGV[0] or usage(1); |     $ARGV[0] or usage(1); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| { | { | ||||||
|     my @meshes = map Slic3r::Format::STL->read_file($_), @ARGV; |     my @models = map Slic3r::Format::STL->read_file($_), @ARGV; | ||||||
|     my $output_file = $ARGV[0]; |     my $output_file = $ARGV[0]; | ||||||
|     $output_file =~ s/\.stl$/.amf.xml/i; |     $output_file =~ s/\.stl$/.amf.xml/i; | ||||||
|      |      | ||||||
|     my $materials = {}; |     my $new_model = Slic3r::Model->new; | ||||||
|     my $meshes_by_material = {}; |      | ||||||
|     if (@meshes == 1) { |     if ($opt{distinct_materials} && @models > 1) { | ||||||
|         $meshes_by_material->{_} = $meshes[0]; |         my $new_object = $new_model->add_object; | ||||||
|  |         for my $m (0 .. $#models) { | ||||||
|  |             my $model = $models[$m]; | ||||||
|  |             my $v_offset = @{$new_object->vertices}; | ||||||
|  |             push @{$new_object->vertices}, @{$model->objects->[0]->vertices}; | ||||||
|  |             my @new_facets = map { | ||||||
|  |                 my $f = [@$_]; | ||||||
|  |                 $f->[$_] += $v_offset for -3..-1; | ||||||
|  |                 $f; | ||||||
|  |             } @{ $model->objects->[0]->volumes->[0]->facets }; | ||||||
|  |              | ||||||
|  |             push @{$new_model->materials}, { Name => basename($ARGV[$m]) }; | ||||||
|  |             $new_object->add_volume( | ||||||
|  |                 material_id => $#{$new_model->materials}, | ||||||
|  |                 facets      => [@new_facets], | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|     } else { |     } else { | ||||||
|         for (0..$#meshes) { |         foreach my $model (@models) { | ||||||
|             $materials->{$_+1} = { Name => basename($ARGV[$_]) }; |             $new_model->add_object( | ||||||
|             $meshes_by_material->{$_+1} = $meshes[$_]; |                 vertices => $model->objects->[0]->vertices, | ||||||
|  |             )->add_volume( | ||||||
|  |                 facets => $model->objects->[0]->volumes->[0]->facets, | ||||||
|  |             ); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     printf "Writing to %s\n", basename($output_file); |     printf "Writing to %s\n", basename($output_file); | ||||||
|     Slic3r::Format::AMF->write_file($output_file, $materials, $meshes_by_material); |     Slic3r::Format::AMF->write_file($output_file, $new_model); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -51,6 +71,7 @@ sub usage { | ||||||
| Usage: amf-to-stl.pl [ OPTIONS ] file.stl [ file2.stl [ file3.stl ] ] | Usage: amf-to-stl.pl [ OPTIONS ] file.stl [ file2.stl [ file3.stl ] ] | ||||||
| 
 | 
 | ||||||
|     --help              Output this usage screen and exit |     --help              Output this usage screen and exit | ||||||
|  |     --distinct-materials Assign each STL file to a different material | ||||||
|      |      | ||||||
| EOF | EOF | ||||||
|     exit ($exit_code || 0); |     exit ($exit_code || 0); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Alessandro Ranellucci
						Alessandro Ranellucci