mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-31 12:41:20 -06:00 
			
		
		
		
	New AMF-to-STL and STL-to-AMF converters
This commit is contained in:
		
							parent
							
								
									79ebb13bdb
								
							
						
					
					
						commit
						776d985b26
					
				
					 6 changed files with 170 additions and 4 deletions
				
			
		
							
								
								
									
										2
									
								
								MANIFEST
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								MANIFEST
									
										
									
									
									
								
							|  | @ -51,5 +51,7 @@ t/fill.t | ||||||
| t/geometry.t | t/geometry.t | ||||||
| t/polyclip.t | t/polyclip.t | ||||||
| t/stl.t | t/stl.t | ||||||
|  | utils/amf-to-stl.pl | ||||||
| utils/post-processing/z-every-line.pl | utils/post-processing/z-every-line.pl | ||||||
| utils/split_stl.pl | utils/split_stl.pl | ||||||
|  | utils/stl-to-amf.pl | ||||||
|  |  | ||||||
|  | @ -1,5 +1,7 @@ | ||||||
| package Slic3r::AMF; | package Slic3r::AMF; | ||||||
| use Moo; | use Moo; | ||||||
|  | 
 | ||||||
|  | use Slic3r::Geometry qw(X Y Z); | ||||||
| use XXX; | use XXX; | ||||||
| 
 | 
 | ||||||
| sub read_file { | sub read_file { | ||||||
|  | @ -25,4 +27,41 @@ sub read_file { | ||||||
|     return Slic3r::TriangleMesh->new(vertices => $vertices, facets => $facets); |     return Slic3r::TriangleMesh->new(vertices => $vertices, facets => $facets); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | sub write_file { | ||||||
|  |     my $self = shift; | ||||||
|  |     my ($file, $mesh) = @_; | ||||||
|  |      | ||||||
|  |     open my $fh, '>', $file; | ||||||
|  |     binmode $fh, ':utf8'; | ||||||
|  |      | ||||||
|  |     printf $fh qq{<?xml version="1.0" encoding="UTF-8"?>\n}; | ||||||
|  |     printf $fh qq{<amf unit="millimeter">\n}; | ||||||
|  |     printf $fh qq{  <metadata type="cad">Slic3r %s</metadata>\n}, $Slic3r::VERSION; | ||||||
|  |     printf $fh qq{  <object id="0">\n}; | ||||||
|  |     printf $fh qq{    <mesh>\n}; | ||||||
|  |     printf $fh qq{      <vertices>\n}; | ||||||
|  |     foreach my $vertex (@{$mesh->vertices}) { | ||||||
|  |         printf $fh qq{        <vertex>\n}; | ||||||
|  |         printf $fh qq{          <coordinates>\n}; | ||||||
|  |         printf $fh qq{            <x>%s</x>\n}, $vertex->[X]; | ||||||
|  |         printf $fh qq{            <y>%s</y>\n}, $vertex->[Y]; | ||||||
|  |         printf $fh qq{            <z>%s</z>\n}, $vertex->[Z]; | ||||||
|  |         printf $fh qq{          </coordinates>\n}; | ||||||
|  |         printf $fh qq{        </vertex>\n}; | ||||||
|  |     } | ||||||
|  |     printf $fh qq{      </vertices>\n}; | ||||||
|  |     printf $fh qq{      <volume>\n}; | ||||||
|  |     foreach my $facet (@{$mesh->facets}) { | ||||||
|  |         printf $fh qq{        <triangle>\n}; | ||||||
|  |         printf $fh qq{          <v%d>%d</v%d>\n}, $_, $facet->[$_], $_ for 1..3; | ||||||
|  |         printf $fh qq{        </triangle>\n}; | ||||||
|  |     } | ||||||
|  |     printf $fh qq{      </volume>\n}; | ||||||
|  |     printf $fh qq{    </mesh>\n}; | ||||||
|  |     printf $fh qq{  </object>\n}; | ||||||
|  |     printf $fh qq{</amf>\n}; | ||||||
|  |      | ||||||
|  |     close $fh; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| 1; | 1; | ||||||
|  |  | ||||||
|  | @ -19,7 +19,7 @@ our @EXPORT_OK = qw( | ||||||
|     polygon_remove_acute_vertices polygon_remove_parallel_continuous_edges |     polygon_remove_acute_vertices polygon_remove_parallel_continuous_edges | ||||||
|     shortest_path collinear scale unscale merge_collinear_lines |     shortest_path collinear scale unscale merge_collinear_lines | ||||||
|     rad2deg_dir bounding_box_center line_intersects_any |     rad2deg_dir bounding_box_center line_intersects_any | ||||||
|     polyline_remove_short_segments |     polyline_remove_short_segments normal triangle_normal | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
| use Slic3r::Geometry::DouglasPeucker qw(Douglas_Peucker); | use Slic3r::Geometry::DouglasPeucker qw(Douglas_Peucker); | ||||||
|  | @ -414,6 +414,25 @@ sub subtract_vectors { | ||||||
|     return [ $line2->[X] - $line1->[X], $line2->[Y] - $line1->[Y] ]; |     return [ $line2->[X] - $line1->[X], $line2->[Y] - $line1->[Y] ]; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | sub normal { | ||||||
|  |     my ($line1, $line2) = @_; | ||||||
|  |      | ||||||
|  |     return [ | ||||||
|  |          ($line1->[Y] * $line2->[Z]) - ($line1->[Z] * $line2->[Y]), | ||||||
|  |         -($line2->[Z] * $line1->[X]) + ($line2->[X] * $line1->[Z]), | ||||||
|  |          ($line1->[X] * $line2->[Y]) - ($line1->[Y] * $line2->[X]), | ||||||
|  |     ]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | sub triangle_normal { | ||||||
|  |     my ($v1, $v2, $v3) = @_; | ||||||
|  |      | ||||||
|  |     my $u = [ map +($v2->[$_] - $v1->[$_]), (X,Y,Z) ]; | ||||||
|  |     my $v = [ map +($v3->[$_] - $v1->[$_]), (X,Y,Z) ]; | ||||||
|  |      | ||||||
|  |     return normal($u, $v); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| # 2D dot product | # 2D dot product | ||||||
| sub dot { | sub dot { | ||||||
|     my ($u, $v) = @_; |     my ($u, $v) = @_; | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| package Slic3r::STL; | package Slic3r::STL; | ||||||
| use Moo; | use Moo; | ||||||
| 
 | 
 | ||||||
| use Slic3r::Geometry qw(X Y Z); | use Slic3r::Geometry qw(X Y Z triangle_normal); | ||||||
| use XXX; | use XXX; | ||||||
| 
 | 
 | ||||||
| sub read_file { | sub read_file { | ||||||
|  | @ -181,7 +181,10 @@ sub _write_binary { | ||||||
|     print $fh pack 'x80'; |     print $fh pack 'x80'; | ||||||
|     print $fh pack 'L', scalar(@{$mesh->facets}); |     print $fh pack 'L', scalar(@{$mesh->facets}); | ||||||
|     foreach my $facet (@{$mesh->facets}) { |     foreach my $facet (@{$mesh->facets}) { | ||||||
|         print $fh pack '(f<3)4S', @{$facet->[0]}, (map @{$mesh->vertices->[$_]}, @$facet[1,2,3]), 0; |         print $fh pack '(f<3)4S', | ||||||
|  |             @{_facet_normal($mesh, $facet)}, | ||||||
|  |             (map @{$mesh->vertices->[$_]}, @$facet[1,2,3]), | ||||||
|  |             0; | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -190,7 +193,7 @@ sub _write_ascii { | ||||||
|      |      | ||||||
|     printf $fh "solid\n"; |     printf $fh "solid\n"; | ||||||
|     foreach my $facet (@{$mesh->facets}) { |     foreach my $facet (@{$mesh->facets}) { | ||||||
|         printf $fh "   facet normal %f %f %f\n", @{$facet->[0]}; |         printf $fh "   facet normal %f %f %f\n", @{_facet_normal($mesh, $facet)}; | ||||||
|         printf $fh "      outer loop\n"; |         printf $fh "      outer loop\n"; | ||||||
|         printf $fh "         vertex %f %f %f\n", @{$mesh->vertices->[$_]} for @$facet[1,2,3]; |         printf $fh "         vertex %f %f %f\n", @{$mesh->vertices->[$_]} for @$facet[1,2,3]; | ||||||
|         printf $fh "      endloop\n"; |         printf $fh "      endloop\n"; | ||||||
|  | @ -199,4 +202,9 @@ sub _write_ascii { | ||||||
|     printf $fh "endsolid\n"; |     printf $fh "endsolid\n"; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | sub _facet_normal { | ||||||
|  |     my ($mesh, $facet) = @_; | ||||||
|  |     return triangle_normal(map $mesh->vertices->[$_], @$facet[1,2,3]); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| 1; | 1; | ||||||
|  |  | ||||||
							
								
								
									
										50
									
								
								utils/amf-to-stl.pl
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										50
									
								
								utils/amf-to-stl.pl
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,50 @@ | ||||||
|  | #!/usr/bin/perl | ||||||
|  | # This script converts an AMF file to STL | ||||||
|  | 
 | ||||||
|  | use strict; | ||||||
|  | use warnings; | ||||||
|  | 
 | ||||||
|  | BEGIN { | ||||||
|  |     use FindBin; | ||||||
|  |     use lib "$FindBin::Bin/../lib"; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | use File::Basename qw(basename); | ||||||
|  | use Getopt::Long qw(:config no_auto_abbrev); | ||||||
|  | use Slic3r; | ||||||
|  | $|++; | ||||||
|  | 
 | ||||||
|  | my %opt = (); | ||||||
|  | { | ||||||
|  |     my %options = ( | ||||||
|  |         'help'                  => sub { usage() }, | ||||||
|  |         'ascii'                 => \$opt{ascii}, | ||||||
|  |     ); | ||||||
|  |     GetOptions(%options) or usage(1); | ||||||
|  |     $ARGV[0] or usage(1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | { | ||||||
|  |     my $mesh = Slic3r::AMF->read_file($ARGV[0]); | ||||||
|  |     my $output_file = $ARGV[0]; | ||||||
|  |     $output_file =~ s/\.amf(?:\.xml)?$/\.stl/i; | ||||||
|  |      | ||||||
|  |     printf "Writing to %s\n", basename($output_file); | ||||||
|  |     Slic3r::STL->write_file($output_file, $mesh, !$opt{ascii}); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | sub usage { | ||||||
|  |     my ($exit_code) = @_; | ||||||
|  |      | ||||||
|  |     print <<"EOF"; | ||||||
|  | Usage: amf-to-stl.pl [ OPTIONS ] file.amf | ||||||
|  | 
 | ||||||
|  |     --help              Output this usage screen and exit | ||||||
|  |     --ascii             Generate ASCII STL files (default: binary) | ||||||
|  |      | ||||||
|  | EOF | ||||||
|  |     exit ($exit_code || 0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | __END__ | ||||||
							
								
								
									
										48
									
								
								utils/stl-to-amf.pl
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										48
									
								
								utils/stl-to-amf.pl
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,48 @@ | ||||||
|  | #!/usr/bin/perl | ||||||
|  | # This script converts a STL file to AMF | ||||||
|  | 
 | ||||||
|  | use strict; | ||||||
|  | use warnings; | ||||||
|  | 
 | ||||||
|  | BEGIN { | ||||||
|  |     use FindBin; | ||||||
|  |     use lib "$FindBin::Bin/../lib"; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | use File::Basename qw(basename); | ||||||
|  | use Getopt::Long qw(:config no_auto_abbrev); | ||||||
|  | use Slic3r; | ||||||
|  | $|++; | ||||||
|  | 
 | ||||||
|  | my %opt = (); | ||||||
|  | { | ||||||
|  |     my %options = ( | ||||||
|  |         'help'                  => sub { usage() }, | ||||||
|  |     ); | ||||||
|  |     GetOptions(%options) or usage(1); | ||||||
|  |     $ARGV[0] or usage(1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | { | ||||||
|  |     my $mesh = Slic3r::STL->read_file($ARGV[0]); | ||||||
|  |     my $output_file = $ARGV[0]; | ||||||
|  |     $output_file =~ s/\.stl$/.amf.xml/i; | ||||||
|  |      | ||||||
|  |     printf "Writing to %s\n", basename($output_file); | ||||||
|  |     Slic3r::AMF->write_file($output_file, $mesh); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | sub usage { | ||||||
|  |     my ($exit_code) = @_; | ||||||
|  |      | ||||||
|  |     print <<"EOF"; | ||||||
|  | Usage: amf-to-stl.pl [ OPTIONS ] file.stl | ||||||
|  | 
 | ||||||
|  |     --help              Output this usage screen and exit | ||||||
|  |      | ||||||
|  | EOF | ||||||
|  |     exit ($exit_code || 0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | __END__ | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Alessandro Ranellucci
						Alessandro Ranellucci