SVG export
This commit is contained in:
parent
5bd16ffed6
commit
32c46f0ea3
@ -93,6 +93,7 @@ The author is Alessandro Ranellucci (me).
|
|||||||
and [input_filename] (default: [input_filename_base].gcode)
|
and [input_filename] (default: [input_filename_base].gcode)
|
||||||
--post-process Generated G-code will be processed with the supplied script;
|
--post-process Generated G-code will be processed with the supplied script;
|
||||||
call this more than once to process through multiple scripts.
|
call this more than once to process through multiple scripts.
|
||||||
|
--export-svg Export a SVG file containing slices instead of G-code.
|
||||||
|
|
||||||
Printer options:
|
Printer options:
|
||||||
--nozzle-diameter Diameter of nozzle in mm (default: 0.5)
|
--nozzle-diameter Diameter of nozzle in mm (default: 0.5)
|
||||||
|
@ -37,12 +37,14 @@ sub OnInit {
|
|||||||
$fileMenu->Append(3, "Slice…");
|
$fileMenu->Append(3, "Slice…");
|
||||||
$fileMenu->Append(4, "Reslice");
|
$fileMenu->Append(4, "Reslice");
|
||||||
$fileMenu->Append(5, "Slice and Save As…");
|
$fileMenu->Append(5, "Slice and Save As…");
|
||||||
|
$fileMenu->Append(6, "Export SVG…");
|
||||||
$menubar->Append($fileMenu, "&File");
|
$menubar->Append($fileMenu, "&File");
|
||||||
EVT_MENU($frame, 1, sub { $panel->save_config });
|
EVT_MENU($frame, 1, sub { $panel->save_config });
|
||||||
EVT_MENU($frame, 2, sub { $panel->load_config });
|
EVT_MENU($frame, 2, sub { $panel->load_config });
|
||||||
EVT_MENU($frame, 3, sub { $panel->do_slice });
|
EVT_MENU($frame, 3, sub { $panel->do_slice });
|
||||||
EVT_MENU($frame, 4, sub { $panel->do_slice(reslice => 1) });
|
EVT_MENU($frame, 4, sub { $panel->do_slice(reslice => 1) });
|
||||||
EVT_MENU($frame, 5, sub { $panel->do_slice(save_as => 1) });
|
EVT_MENU($frame, 5, sub { $panel->do_slice(save_as => 1) });
|
||||||
|
EVT_MENU($frame, 6, sub { $panel->do_slice(save_as => 1, export_svg => 1) });
|
||||||
|
|
||||||
$box->SetSizeHints($frame);
|
$box->SetSizeHints($frame);
|
||||||
$frame->SetSizer($box);
|
$frame->SetSizer($box);
|
||||||
|
@ -222,7 +222,8 @@ sub do_slice {
|
|||||||
}
|
}
|
||||||
} elsif ($params{save_as}) {
|
} elsif ($params{save_as}) {
|
||||||
my $output_file = $skein->expanded_output_filepath;
|
my $output_file = $skein->expanded_output_filepath;
|
||||||
my $dlg = Wx::FileDialog->new($self, 'Save gcode file as:', dirname($output_file),
|
$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:', dirname($output_file),
|
||||||
basename($output_file), $gcode_wildcard, wxFD_SAVE);
|
basename($output_file), $gcode_wildcard, wxFD_SAVE);
|
||||||
return if $dlg->ShowModal != wxID_OK;
|
return if $dlg->ShowModal != wxID_OK;
|
||||||
$skein->output_file($dlg->GetPath);
|
$skein->output_file($dlg->GetPath);
|
||||||
@ -237,15 +238,22 @@ sub do_slice {
|
|||||||
{
|
{
|
||||||
my @warnings = ();
|
my @warnings = ();
|
||||||
local $SIG{__WARN__} = sub { push @warnings, $_[0] };
|
local $SIG{__WARN__} = sub { push @warnings, $_[0] };
|
||||||
$skein->go;
|
if ($params{export_svg}) {
|
||||||
|
$skein->export_svg;
|
||||||
|
} else {
|
||||||
|
$skein->go;
|
||||||
|
}
|
||||||
$self->catch_warning->($_) for @warnings;
|
$self->catch_warning->($_) for @warnings;
|
||||||
}
|
}
|
||||||
$process_dialog->Destroy;
|
$process_dialog->Destroy;
|
||||||
undef $process_dialog;
|
undef $process_dialog;
|
||||||
|
|
||||||
my $message = sprintf "%s was successfully sliced in %d minutes and %.3f seconds.",
|
my $message = "$input_file_basename was successfully sliced";
|
||||||
$input_file_basename, int($skein->processing_time/60),
|
$message .= sprintf " in %d minutes and %.3f seconds",
|
||||||
$skein->processing_time - int($skein->processing_time/60)*60;
|
int($skein->processing_time/60),
|
||||||
|
$skein->processing_time - int($skein->processing_time/60)*60
|
||||||
|
if $skein->processing_time;
|
||||||
|
$message .= ".";
|
||||||
eval {
|
eval {
|
||||||
$self->{growler}->notify(Event => 'SKEIN_DONE', Title => 'Slicing Done!', Message => $message)
|
$self->{growler}->notify(Event => 'SKEIN_DONE', Title => 'Slicing Done!', Message => $message)
|
||||||
if ($self->{growler});
|
if ($self->{growler});
|
||||||
|
@ -3,7 +3,7 @@ use Moo;
|
|||||||
|
|
||||||
use Config;
|
use Config;
|
||||||
use File::Basename qw(basename fileparse);
|
use File::Basename qw(basename fileparse);
|
||||||
use Slic3r::Geometry qw(PI);
|
use Slic3r::Geometry qw(PI unscale);
|
||||||
use Time::HiRes qw(gettimeofday tv_interval);
|
use Time::HiRes qw(gettimeofday tv_interval);
|
||||||
use XXX;
|
use XXX;
|
||||||
|
|
||||||
@ -17,14 +17,9 @@ has 'output_file' => (is => 'rw', required => 0);
|
|||||||
has 'status_cb' => (is => 'rw', required => 0, default => sub { sub {} });
|
has 'status_cb' => (is => 'rw', required => 0, default => sub { sub {} });
|
||||||
has 'processing_time' => (is => 'rw', required => 0);
|
has 'processing_time' => (is => 'rw', required => 0);
|
||||||
|
|
||||||
sub go {
|
sub slice_input {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $t0 = [gettimeofday];
|
|
||||||
|
|
||||||
# skein the STL into layers
|
|
||||||
# each layer has surfaces with holes
|
|
||||||
$self->status_cb->(5, "Processing input file " . $self->input_file);
|
|
||||||
$self->status_cb->(10, "Processing triangulated mesh");
|
|
||||||
my $print;
|
my $print;
|
||||||
if ($self->input_file =~ /\.stl$/i) {
|
if ($self->input_file =~ /\.stl$/i) {
|
||||||
my $mesh = Slic3r::Format::STL->read_file($self->input_file);
|
my $mesh = Slic3r::Format::STL->read_file($self->input_file);
|
||||||
@ -37,6 +32,17 @@ sub go {
|
|||||||
} else {
|
} else {
|
||||||
die "Input file must have .stl or .amf(.xml) extension\n";
|
die "Input file must have .stl or .amf(.xml) extension\n";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub go {
|
||||||
|
my $self = shift;
|
||||||
|
my $t0 = [gettimeofday];
|
||||||
|
|
||||||
|
# skein the STL into layers
|
||||||
|
# each layer has surfaces with holes
|
||||||
|
$self->status_cb->(5, "Processing input file " . $self->input_file);
|
||||||
|
$self->status_cb->(10, "Processing triangulated mesh");
|
||||||
|
my $print = $self->slice_input;
|
||||||
|
|
||||||
# make perimeters
|
# make perimeters
|
||||||
# this will add a set of extrusion loops to each layer
|
# this will add a set of extrusion loops to each layer
|
||||||
@ -152,6 +158,49 @@ sub go {
|
|||||||
$print->total_extrusion_length, $print->total_extrusion_volume;
|
$print->total_extrusion_length, $print->total_extrusion_volume;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub export_svg {
|
||||||
|
my $self = shift;
|
||||||
|
|
||||||
|
my $print = $self->slice_input;
|
||||||
|
my $output_file = $self->expanded_output_filepath;
|
||||||
|
$output_file =~ s/\.gcode$/.svg/i;
|
||||||
|
|
||||||
|
open my $fh, ">", $output_file or die "Failed to open $output_file for writing\n";
|
||||||
|
print "Exporting to $output_file...";
|
||||||
|
print $fh sprintf <<"EOF", unscale($print->total_x_length), unscale($print->total_y_length);
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||||
|
<svg width="%s" height="%s" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
EOF
|
||||||
|
|
||||||
|
my $print_polygon = sub {
|
||||||
|
my ($polygon, $fill) = @_;
|
||||||
|
printf $fh qq{ <polygon points="%s" style="fill: %s" />},
|
||||||
|
(join ' ', map { join ',', map unscale $_, @$_ } @$polygon), $fill;
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach my $layer (@{$print->layers}) {
|
||||||
|
printf $fh qq{ <g id="layer%d">\n}, $layer->id;
|
||||||
|
# sort slices so that the outermost ones come first
|
||||||
|
my @slices = sort { $a->expolygon->contour->encloses_point($b->expolygon->contour->[0]) ? 0 : 1 } @{$layer->slices};
|
||||||
|
foreach my $slice (@slices) {
|
||||||
|
$print_polygon->($slice->expolygon->contour, 'black');
|
||||||
|
$print_polygon->($_, 'white') for $slice->expolygon->holes;
|
||||||
|
}
|
||||||
|
print $fh qq{ </g>\n};
|
||||||
|
}
|
||||||
|
|
||||||
|
print $fh <<"EOF";
|
||||||
|
<!--
|
||||||
|
Generated using Slic3r $Slic3r::VERSION
|
||||||
|
http://slic3r.org/
|
||||||
|
-->
|
||||||
|
</svg>
|
||||||
|
EOF
|
||||||
|
close $fh;
|
||||||
|
print "Done.\n";
|
||||||
|
}
|
||||||
|
|
||||||
# this method will return the value of $self->output_file after expanding its
|
# this method will return the value of $self->output_file after expanding its
|
||||||
# format variables with their values
|
# format variables with their values
|
||||||
sub expanded_output_filepath {
|
sub expanded_output_filepath {
|
||||||
|
@ -26,6 +26,7 @@ my %cli_options = ();
|
|||||||
'load=s@' => \$opt{load},
|
'load=s@' => \$opt{load},
|
||||||
'ignore-nonexistent-config' => \$opt{ignore_nonexistent_config},
|
'ignore-nonexistent-config' => \$opt{ignore_nonexistent_config},
|
||||||
'threads|j=i' => \$Slic3r::threads,
|
'threads|j=i' => \$Slic3r::threads,
|
||||||
|
'export-svg' => \$opt{export_svg},
|
||||||
);
|
);
|
||||||
foreach my $opt_key (keys %$Slic3r::Config::Options) {
|
foreach my $opt_key (keys %$Slic3r::Config::Options) {
|
||||||
my $opt = $Slic3r::Config::Options->{$opt_key};
|
my $opt = $Slic3r::Config::Options->{$opt_key};
|
||||||
@ -81,7 +82,11 @@ if (@ARGV) {
|
|||||||
printf "=> $message\n";
|
printf "=> $message\n";
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
$skein->go;
|
if ($opt{export_svg}) {
|
||||||
|
$skein->export_svg;
|
||||||
|
} else {
|
||||||
|
$skein->go;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
usage(1) unless $opt{save};
|
usage(1) unless $opt{save};
|
||||||
@ -111,6 +116,7 @@ Usage: slic3r.pl [ OPTIONS ] file.stl
|
|||||||
and [input_filename] (default: $Slic3r::output_filename_format)
|
and [input_filename] (default: $Slic3r::output_filename_format)
|
||||||
--post-process Generated G-code will be processed with the supplied script;
|
--post-process Generated G-code will be processed with the supplied script;
|
||||||
call this more than once to process through multiple scripts.
|
call this more than once to process through multiple scripts.
|
||||||
|
--export-svg Export a SVG file containing slices instead of G-code.
|
||||||
|
|
||||||
Printer options:
|
Printer options:
|
||||||
--nozzle-diameter Diameter of nozzle in mm (default: $Slic3r::nozzle_diameter)
|
--nozzle-diameter Diameter of nozzle in mm (default: $Slic3r::nozzle_diameter)
|
||||||
|
Loading…
Reference in New Issue
Block a user