2011-10-03 09:55:32 +00:00
|
|
|
package Slic3r::Skein;
|
|
|
|
use Moo;
|
|
|
|
|
|
|
|
use Time::HiRes qw(gettimeofday tv_interval);
|
2011-10-04 20:27:45 +00:00
|
|
|
use XXX;
|
2011-10-03 09:55:32 +00:00
|
|
|
|
|
|
|
has 'input_file' => (is => 'ro', required => 1);
|
|
|
|
has 'output_file' => (is => 'rw', required => 0);
|
2011-11-26 15:19:30 +00:00
|
|
|
has 'status_cb' => (is => 'rw', required => 0, default => sub { sub {} });
|
|
|
|
has 'processing_time' => (is => 'rw', required => 0);
|
2011-10-03 09:55:32 +00:00
|
|
|
|
|
|
|
sub go {
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
die "Input file must have .stl extension\n"
|
|
|
|
if $self->input_file !~ /\.stl$/i;
|
|
|
|
|
|
|
|
my $t0 = [gettimeofday];
|
2011-10-07 17:07:57 +00:00
|
|
|
|
|
|
|
# skein the STL into layers
|
2011-10-09 17:47:21 +00:00
|
|
|
# each layer has surfaces with holes
|
2011-11-26 15:19:30 +00:00
|
|
|
$self->status_cb->(10, "Processing triangulated mesh...");
|
2011-11-27 10:40:03 +00:00
|
|
|
my $print;
|
|
|
|
{
|
|
|
|
my $mesh = Slic3r::STL->read_file($self->input_file);
|
|
|
|
$mesh->check_manifoldness;
|
|
|
|
$print = Slic3r::Print->new_from_mesh($mesh);
|
|
|
|
}
|
2011-10-07 17:07:57 +00:00
|
|
|
|
2011-11-23 11:29:27 +00:00
|
|
|
# make skirt
|
2011-11-26 15:19:30 +00:00
|
|
|
$self->status_cb->(15, "Generating skirt...");
|
2011-11-23 11:29:27 +00:00
|
|
|
$print->extrude_skirt;
|
|
|
|
|
|
|
|
# make perimeters
|
|
|
|
# this will add a set of extrusion loops to each layer
|
|
|
|
# as well as generate infill boundaries
|
2011-11-26 15:19:30 +00:00
|
|
|
$self->status_cb->(20, "Generating perimeters...");
|
2011-11-23 11:29:27 +00:00
|
|
|
{
|
|
|
|
my $perimeter_maker = Slic3r::Perimeter->new;
|
|
|
|
$perimeter_maker->make_perimeter($_) for @{$print->layers};
|
|
|
|
}
|
|
|
|
|
2011-11-27 09:12:44 +00:00
|
|
|
# this will clip $layer->surfaces to the infill boundaries
|
|
|
|
# and split them in top/bottom/internal surfaces;
|
2011-11-26 15:19:30 +00:00
|
|
|
$self->status_cb->(30, "Detecting solid surfaces...");
|
2011-10-09 17:47:21 +00:00
|
|
|
$print->detect_surfaces_type;
|
|
|
|
|
2011-12-03 17:31:31 +00:00
|
|
|
# decide what surfaces are to be filled
|
2011-11-30 19:32:28 +00:00
|
|
|
$self->status_cb->(35, "Preparing infill surfaces...");
|
|
|
|
$_->prepare_fill_surfaces for @{$print->layers};
|
|
|
|
|
2011-10-07 17:07:57 +00:00
|
|
|
# this will remove unprintable surfaces
|
|
|
|
# (those that are too tight for extrusion)
|
2011-11-26 15:19:30 +00:00
|
|
|
$self->status_cb->(40, "Cleaning up...");
|
2011-11-16 08:52:09 +00:00
|
|
|
$_->remove_small_surfaces for @{$print->layers};
|
2011-10-07 17:07:57 +00:00
|
|
|
|
2011-11-23 11:29:27 +00:00
|
|
|
# this will detect bridges and reverse bridges
|
|
|
|
# and rearrange top/bottom/internal surfaces
|
2011-11-26 15:19:30 +00:00
|
|
|
$self->status_cb->(45, "Detect bridges...");
|
2011-11-16 08:52:09 +00:00
|
|
|
$_->process_bridges for @{$print->layers};
|
2011-10-07 17:07:57 +00:00
|
|
|
|
|
|
|
# this will remove unprintable perimeter loops
|
|
|
|
# (those that are too tight for extrusion)
|
2011-11-26 15:19:30 +00:00
|
|
|
$self->status_cb->(50, "Cleaning up the perimeters...");
|
2011-11-16 08:52:09 +00:00
|
|
|
$_->remove_small_perimeters for @{$print->layers};
|
2011-10-07 17:07:57 +00:00
|
|
|
|
|
|
|
# detect which fill surfaces are near external layers
|
|
|
|
# they will be split in internal and internal-solid surfaces
|
2011-11-26 15:19:30 +00:00
|
|
|
$self->status_cb->(60, "Generating horizontal shells...");
|
2011-10-04 20:27:45 +00:00
|
|
|
$print->discover_horizontal_shells;
|
|
|
|
|
2011-10-18 13:57:53 +00:00
|
|
|
# combine fill surfaces to honor the "infill every N layers" option
|
2011-11-26 15:19:30 +00:00
|
|
|
$self->status_cb->(70, "Combining infill...");
|
2011-10-18 13:57:53 +00:00
|
|
|
$print->infill_every_layers;
|
|
|
|
|
2011-10-07 17:07:57 +00:00
|
|
|
# this will generate extrusion paths for each layer
|
2011-11-26 15:19:30 +00:00
|
|
|
$self->status_cb->(80, "Infilling layers...");
|
2011-11-23 11:29:27 +00:00
|
|
|
{
|
|
|
|
my $fill_maker = Slic3r::Fill->new('print' => $print);
|
|
|
|
$fill_maker->make_fill($_) for @{$print->layers};
|
|
|
|
}
|
2011-10-03 09:55:32 +00:00
|
|
|
|
2011-10-07 17:07:57 +00:00
|
|
|
# output everything to a GCODE file
|
2011-11-26 15:19:30 +00:00
|
|
|
$self->status_cb->(90, "Exporting GCODE...");
|
2011-10-03 09:55:32 +00:00
|
|
|
if (!$self->output_file) {
|
|
|
|
my $output_file = $self->input_file;
|
|
|
|
$output_file =~ s/\.stl$/.gcode/i;
|
|
|
|
$self->output_file($output_file);
|
|
|
|
}
|
|
|
|
$print->export_gcode($self->output_file);
|
|
|
|
|
2011-10-07 17:07:57 +00:00
|
|
|
# output some statistics
|
2011-11-26 15:19:30 +00:00
|
|
|
$self->processing_time(tv_interval($t0));
|
2011-10-03 09:55:32 +00:00
|
|
|
printf "Done. Process took %d minutes and %.3f seconds\n",
|
2011-11-26 15:19:30 +00:00
|
|
|
int($self->processing_time/60),
|
|
|
|
$self->processing_time - int($self->processing_time/60)*60;
|
2011-10-07 17:07:57 +00:00
|
|
|
|
|
|
|
# TODO: more statistics!
|
2011-10-03 09:55:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
1;
|