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/polyclip.t
|
||||
t/stl.t
|
||||
utils/amf-to-stl.pl
|
||||
utils/post-processing/z-every-line.pl
|
||||
utils/split_stl.pl
|
||||
utils/stl-to-amf.pl
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package Slic3r::AMF;
|
||||
use Moo;
|
||||
|
||||
use Slic3r::Geometry qw(X Y Z);
|
||||
use XXX;
|
||||
|
||||
sub read_file {
|
||||
|
@ -25,4 +27,41 @@ sub read_file {
|
|||
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;
|
||||
|
|
|
@ -19,7 +19,7 @@ our @EXPORT_OK = qw(
|
|||
polygon_remove_acute_vertices polygon_remove_parallel_continuous_edges
|
||||
shortest_path collinear scale unscale merge_collinear_lines
|
||||
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);
|
||||
|
@ -414,6 +414,25 @@ sub subtract_vectors {
|
|||
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
|
||||
sub dot {
|
||||
my ($u, $v) = @_;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package Slic3r::STL;
|
||||
use Moo;
|
||||
|
||||
use Slic3r::Geometry qw(X Y Z);
|
||||
use Slic3r::Geometry qw(X Y Z triangle_normal);
|
||||
use XXX;
|
||||
|
||||
sub read_file {
|
||||
|
@ -181,7 +181,10 @@ sub _write_binary {
|
|||
print $fh pack 'x80';
|
||||
print $fh pack 'L', scalar(@{$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";
|
||||
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 " vertex %f %f %f\n", @{$mesh->vertices->[$_]} for @$facet[1,2,3];
|
||||
printf $fh " endloop\n";
|
||||
|
@ -199,4 +202,9 @@ sub _write_ascii {
|
|||
printf $fh "endsolid\n";
|
||||
}
|
||||
|
||||
sub _facet_normal {
|
||||
my ($mesh, $facet) = @_;
|
||||
return triangle_normal(map $mesh->vertices->[$_], @$facet[1,2,3]);
|
||||
}
|
||||
|
||||
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…
Reference in a new issue