Merge branch 'xs-model'

This commit is contained in:
Alessandro Ranellucci 2013-12-20 01:41:13 +01:00
commit 1b9079ffbe
10 changed files with 292 additions and 64 deletions

View File

@ -143,6 +143,7 @@ sub thread_cleanup {
*Slic3r::Polygon::DESTROY = sub {}; *Slic3r::Polygon::DESTROY = sub {};
*Slic3r::Polyline::DESTROY = sub {}; *Slic3r::Polyline::DESTROY = sub {};
*Slic3r::Polyline::Collection::DESTROY = sub {}; *Slic3r::Polyline::Collection::DESTROY = sub {};
*Slic3r::Print::State::DESTROY = sub {};
*Slic3r::Surface::DESTROY = sub {}; *Slic3r::Surface::DESTROY = sub {};
*Slic3r::Surface::Collection::DESTROY = sub {}; *Slic3r::Surface::Collection::DESTROY = sub {};
*Slic3r::TriangleMesh::DESTROY = sub {}; *Slic3r::TriangleMesh::DESTROY = sub {};

View File

@ -9,6 +9,7 @@ use Slic3r::Geometry qw(X Y Z X1 Y1 X2 Y2 MIN MAX PI scale unscale move_points c
convex_hull); convex_hull);
use Slic3r::Geometry::Clipper qw(diff_ex union_ex union_pt intersection_ex intersection offset use Slic3r::Geometry::Clipper qw(diff_ex union_ex union_pt intersection_ex intersection offset
offset2 union union_pt_chained JT_ROUND JT_SQUARE); offset2 union union_pt_chained JT_ROUND JT_SQUARE);
use Slic3r::Print::State ':steps';
has 'config' => (is => 'rw', default => sub { Slic3r::Config->new_from_defaults }, trigger => \&init_config); has 'config' => (is => 'rw', default => sub { Slic3r::Config->new_from_defaults }, trigger => \&init_config);
has 'extra_variables' => (is => 'rw', default => sub {{}}); has 'extra_variables' => (is => 'rw', default => sub {{}});
@ -19,6 +20,7 @@ has 'regions' => (is => 'rw', default => sub {[]});
has 'support_material_flow' => (is => 'rw'); has 'support_material_flow' => (is => 'rw');
has 'first_layer_support_material_flow' => (is => 'rw'); has 'first_layer_support_material_flow' => (is => 'rw');
has 'has_support_material' => (is => 'lazy'); has 'has_support_material' => (is => 'lazy');
has '_state' => (is => 'ro', default => sub { Slic3r::Print::State->new });
# ordered collection of extrusion paths to build skirt loops # ordered collection of extrusion paths to build skirt loops
has 'skirt' => (is => 'rw', default => sub { Slic3r::ExtrusionPath::Collection->new }); has 'skirt' => (is => 'rw', default => sub { Slic3r::ExtrusionPath::Collection->new });
@ -135,19 +137,29 @@ sub add_model_object {
@{$self->extra_variables}{qw(input_filename input_filename_base)} = parse_filename($input_file); @{$self->extra_variables}{qw(input_filename input_filename_base)} = parse_filename($input_file);
} }
} }
# TODO: invalidate skirt and brim
$self->_state->invalidate(STEP_SKIRT);
$self->_state->invalidate(STEP_BRIM);
} }
sub delete_object { sub delete_object {
my ($self, $obj_idx) = @_; my ($self, $obj_idx) = @_;
splice @{$self->objects}, $obj_idx, 1; splice @{$self->objects}, $obj_idx, 1;
# TODO: invalidate skirt and brim # TODO: purge unused regions
$self->_state->invalidate(STEP_SKIRT);
$self->_state->invalidate(STEP_BRIM);
} }
sub delete_all_objects { sub delete_all_objects {
my ($self) = @_; my ($self) = @_;
@{$self->objects} = (); @{$self->objects} = ();
# TODO: invalidate skirt and brim @{$self->regions} = ();
$self->_state->invalidate(STEP_SKIRT);
$self->_state->invalidate(STEP_BRIM);
} }
sub validate { sub validate {
@ -324,108 +336,132 @@ sub _simplify_slices {
sub process { sub process {
my ($self) = @_; my ($self) = @_;
$self->init_extruders;
my $status_cb = $self->status_cb // sub {}; my $status_cb = $self->status_cb // sub {};
my $print_step = sub {
my ($step, $cb) = @_;
if (!$self->_state->done($step)) {
$self->_state->set_started($step);
$cb->();
### Re-enable this for step-based slicing:
### $self->_state->set_done($step);
}
};
my $object_step = sub {
my ($step, $cb) = @_;
for my $obj_idx (0..$#{$self->objects}) {
my $object = $self->objects->[$obj_idx];
if (!$object->_state->done($step)) {
$object->_state->set_started($step);
$cb->($obj_idx);
### Re-enable this for step-based slicing:
### $object->_state->set_done($step);
}
}
};
# STEP_INIT_EXTRUDERS
$print_step->(STEP_INIT_EXTRUDERS, sub {
$self->init_extruders;
});
# STEP_SLICE
# skein the STL into layers # skein the STL into layers
# each layer has surfaces with holes # each layer has surfaces with holes
$status_cb->(10, "Processing triangulated mesh"); $status_cb->(10, "Processing triangulated mesh");
$_->slice for @{$self->objects}; $object_step->(STEP_SLICE, sub {
$self->objects->[$_[0]]->slice;
});
# remove empty layers and abort if there are no more
# as some algorithms assume all objects have at least one layer
# note: this will change object indexes
@{$self->objects} = grep @{$_->layers}, @{$self->objects};
die "No layers were detected. You might want to repair your STL file(s) or check their size and retry.\n" die "No layers were detected. You might want to repair your STL file(s) or check their size and retry.\n"
if !@{$self->objects}; if !grep @{$_->layers}, @{$self->objects};
if ($Slic3r::Config->resolution) {
$status_cb->(15, "Simplifying input");
$self->_simplify_slices(scale $Slic3r::Config->resolution);
}
# 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
# as well as generate infill boundaries # as well as generate infill boundaries
$status_cb->(20, "Generating perimeters"); $status_cb->(20, "Generating perimeters");
$_->make_perimeters for @{$self->objects}; $object_step->(STEP_PERIMETERS, sub {
$self->objects->[$_[0]]->make_perimeters;
});
# simplify slices (both layer and region slices), $status_cb->(30, "Preparing infill");
# we only need the max resolution for perimeters $object_step->(STEP_PREPARE_INFILL, sub {
$self->_simplify_slices(&Slic3r::SCALED_RESOLUTION); my $object = $self->objects->[$_[0]];
# this will assign a type (top/bottom/internal) to $layerm->slices # this will assign a type (top/bottom/internal) to $layerm->slices
# and transform $layerm->fill_surfaces from expolygon # and transform $layerm->fill_surfaces from expolygon
# to typed top/bottom/internal surfaces; # to typed top/bottom/internal surfaces;
$status_cb->(30, "Detecting solid surfaces"); $object->detect_surfaces_type;
$_->detect_surfaces_type for @{$self->objects};
# decide what surfaces are to be filled # decide what surfaces are to be filled
$status_cb->(35, "Preparing infill surfaces"); $_->prepare_fill_surfaces for map @{$_->regions}, @{$object->layers};
$_->prepare_fill_surfaces for map @{$_->regions}, map @{$_->layers}, @{$self->objects};
# this will detect bridges and reverse bridges # this will detect bridges and reverse bridges
# and rearrange top/bottom/internal surfaces # and rearrange top/bottom/internal surfaces
$status_cb->(45, "Detect bridges"); $object->process_external_surfaces;
$_->process_external_surfaces for @{$self->objects};
# detect which fill surfaces are near external layers # detect which fill surfaces are near external layers
# they will be split in internal and internal-solid surfaces # they will be split in internal and internal-solid surfaces
$status_cb->(60, "Generating horizontal shells"); $object->discover_horizontal_shells;
$_->discover_horizontal_shells for @{$self->objects}; $object->clip_fill_surfaces;
$_->clip_fill_surfaces for @{$self->objects};
# the following step needs to be done before combination because it may need
# to remove only half of the combined infill
$_->bridge_over_infill for @{$self->objects};
# combine fill surfaces to honor the "infill every N layers" option # the following step needs to be done before combination because it may need
$status_cb->(70, "Combining infill"); # to remove only half of the combined infill
$_->combine_infill for @{$self->objects}; $object->bridge_over_infill;
# combine fill surfaces to honor the "infill every N layers" option
$object->combine_infill;
});
# this will generate extrusion paths for each layer # this will generate extrusion paths for each layer
$status_cb->(80, "Infilling layers"); $status_cb->(70, "Infilling layers");
{ $object_step->(STEP_INFILL, sub {
my $object = $self->objects->[$_[0]];
Slic3r::parallelize( Slic3r::parallelize(
items => sub { items => sub {
my @items = (); # [obj_idx, layer_id] my @items = (); # [layer_id, region_id]
for my $obj_idx (0 .. $#{$self->objects}) { for my $region_id (0 .. ($self->regions_count-1)) {
for my $region_id (0 .. ($self->regions_count-1)) { push @items, map [$_, $region_id], 0..($object->layer_count-1);
push @items, map [$obj_idx, $_, $region_id], 0..($self->objects->[$obj_idx]->layer_count-1);
}
} }
@items; @items;
}, },
thread_cb => sub { thread_cb => sub {
my $q = shift; my $q = shift;
while (defined (my $obj_layer = $q->dequeue)) { while (defined (my $obj_layer = $q->dequeue)) {
my ($obj_idx, $layer_id, $region_id) = @$obj_layer; my ($layer_id, $region_id) = @$obj_layer;
my $object = $self->objects->[$obj_idx];
my $layerm = $object->layers->[$layer_id]->regions->[$region_id]; my $layerm = $object->layers->[$layer_id]->regions->[$region_id];
$layerm->fills->append( $object->fill_maker->make_fill($layerm) ); $layerm->fills->append( $object->fill_maker->make_fill($layerm) );
} }
}, },
collect_cb => sub {}, collect_cb => sub {},
no_threads_cb => sub { no_threads_cb => sub {
foreach my $layerm (map @{$_->regions}, map @{$_->layers}, @{$self->objects}) { foreach my $layerm (map @{$_->regions}, @{$object->layers}) {
$layerm->fills->append($layerm->layer->object->fill_maker->make_fill($layerm)); $layerm->fills->append($object->fill_maker->make_fill($layerm));
} }
}, },
); );
}
### we could free memory now, but this would make this step not idempotent
### $_->fill_surfaces->clear for map @{$_->regions}, @{$object->layers};
});
# generate support material # generate support material
if ($self->has_support_material) { $status_cb->(85, "Generating support material") if $self->has_support_material;
$status_cb->(85, "Generating support material"); $object_step->(STEP_SUPPORTMATERIAL, sub {
$_->generate_support_material for @{$self->objects}; $self->objects->[$_[0]]->generate_support_material;
} });
# free memory (note that support material needs fill_surfaces)
$_->fill_surfaces->clear for map @{$_->regions}, map @{$_->layers}, @{$self->objects};
# make skirt # make skirt
$status_cb->(88, "Generating skirt"); $status_cb->(88, "Generating skirt");
$self->make_skirt; $print_step->(STEP_SKIRT, sub {
$self->make_brim; # must come after make_skirt $self->make_skirt;
});
$status_cb->(88, "Generating skirt");
$print_step->(STEP_BRIM, sub {
$self->make_brim; # must come after make_skirt
});
# time to make some statistics # time to make some statistics
if (0) { if (0) {
@ -945,4 +981,25 @@ sub apply_extra_variables {
$self->extra_variables->{$_} = $extra->{$_} for keys %$extra; $self->extra_variables->{$_} = $extra->{$_} for keys %$extra;
} }
sub invalidate_step {
my ($self, $step, $obj_idx) = @_;
# invalidate $step in the correct state object
if ($Slic3r::Print::State::print_step->{$step}) {
$self->_state->invalidate($step);
} else {
# object step
if (defined $obj_idx) {
$self->objects->[$obj_idx]->_state->invalidate($step);
} else {
$_->_state->invalidate($step) for @{$self->objects};
}
}
# recursively invalidate steps depending on $step
$self->invalidate_step($_)
for grep { grep { $_ == $step } @{$Slic3r::Print::State::prereqs{$_}} }
keys %Slic3r::Print::State::prereqs;
}
1; 1;

View File

@ -5,6 +5,7 @@ use List::Util qw(min max sum first);
use Slic3r::Geometry qw(X Y Z PI scale unscale deg2rad rad2deg scaled_epsilon chained_path); use Slic3r::Geometry qw(X Y Z PI scale unscale deg2rad rad2deg scaled_epsilon chained_path);
use Slic3r::Geometry::Clipper qw(diff diff_ex intersection intersection_ex union union_ex use Slic3r::Geometry::Clipper qw(diff diff_ex intersection intersection_ex union union_ex
offset offset_ex offset2 offset2_ex CLIPPER_OFFSET_SCALE JT_MITER); offset offset_ex offset2 offset2_ex CLIPPER_OFFSET_SCALE JT_MITER);
use Slic3r::Print::State ':steps';
use Slic3r::Surface ':types'; use Slic3r::Surface ':types';
has 'print' => (is => 'ro', weak_ref => 1, required => 1); has 'print' => (is => 'ro', weak_ref => 1, required => 1);
@ -21,6 +22,7 @@ has '_shifted_copies' => (is => 'rw'); # Slic3r::Point objects in scaled G-co
has 'layers' => (is => 'rw', default => sub { [] }); has 'layers' => (is => 'rw', default => sub { [] });
has 'support_layers' => (is => 'rw', default => sub { [] }); has 'support_layers' => (is => 'rw', default => sub { [] });
has 'fill_maker' => (is => 'lazy'); has 'fill_maker' => (is => 'lazy');
has '_state' => (is => 'ro', default => sub { Slic3r::Print::State->new });
sub BUILD { sub BUILD {
my $self = shift; my $self = shift;
@ -70,6 +72,9 @@ sub _trigger_copies {
$c; $c;
} @{$self->copies}[@{chained_path($self->copies)}] } @{$self->copies}[@{chained_path($self->copies)}]
]); ]);
$self->print->_state->invalidate(STEP_SKIRT);
$self->print->_state->invalidate(STEP_BRIM);
} }
# in unscaled coordinates # in unscaled coordinates
@ -273,6 +278,11 @@ sub slice {
$self->layers->[$i]->id($i); $self->layers->[$i]->id($i);
} }
} }
# simplify slices if required
if ($self->config->resolution) {
$self->_simplify_slices(scale($self->config->resolution));
}
} }
sub make_perimeters { sub make_perimeters {
@ -348,6 +358,11 @@ sub make_perimeters {
$_->make_perimeters for @{$self->layers}; $_->make_perimeters for @{$self->layers};
}, },
); );
# simplify slices (both layer and region slices),
# we only need the max resolution for perimeters
### This makes this method not-idempotent, so we keep it disabled for now.
###$self->_simplify_slices(&Slic3r::SCALED_RESOLUTION);
} }
sub detect_surfaces_type { sub detect_surfaces_type {
@ -850,4 +865,13 @@ sub generate_support_material {
->generate($self); ->generate($self);
} }
sub _simplify_slices {
my ($self, $distance) = @_;
foreach my $layer (@{$self->layers}) {
$layer->slices->simplify($distance);
$_->slices->simplify($distance) for @{$layer->regions};
}
}
1; 1;

28
lib/Slic3r/Print/State.pm Normal file
View File

@ -0,0 +1,28 @@
package Slic3r::Print::State;
use strict;
use warnings;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(STEP_INIT_EXTRUDERS STEP_SLICE STEP_PERIMETERS STEP_PREPARE_INFILL
STEP_INFILL STEP_SUPPORTMATERIAL STEP_SKIRT STEP_BRIM);
our %EXPORT_TAGS = (steps => \@EXPORT_OK);
our %print_steps = map { $_ => 1 } (
STEP_INIT_EXTRUDERS,
STEP_SKIRT,
STEP_BRIM,
);
our %prereqs = (
STEP_INIT_EXTRUDERS => [],
STEP_SLICE => [],
STEP_PERIMETERS => [STEP_SLICE, STEP_INIT_EXTRUDERS],
STEP_PREPARE_INFILL => [STEP_PERIMETERS],
STEP_INFILL => [STEP_INFILL],
STEP_SUPPORTMATERIAL => [STEP_SLICE, STEP_INIT_EXTRUDERS],
STEP_SKIRT => [STEP_PERIMETERS, STEP_INFILL],
STEP_BRIM => [STEP_PERIMETERS, STEP_INFILL, STEP_SKIRT],
);
1;

View File

@ -35,6 +35,8 @@ src/Polyline.cpp
src/Polyline.hpp src/Polyline.hpp
src/PolylineCollection.cpp src/PolylineCollection.cpp
src/PolylineCollection.hpp src/PolylineCollection.hpp
src/PrintState.cpp
src/PrintState.hpp
src/ppport.h src/ppport.h
src/Surface.cpp src/Surface.cpp
src/Surface.hpp src/Surface.hpp
@ -72,6 +74,7 @@ xsp/Point.xsp
xsp/Polygon.xsp xsp/Polygon.xsp
xsp/Polyline.xsp xsp/Polyline.xsp
xsp/PolylineCollection.xsp xsp/PolylineCollection.xsp
xsp/PrintState.xsp
xsp/Surface.xsp xsp/Surface.xsp
xsp/SurfaceCollection.xsp xsp/SurfaceCollection.xsp
xsp/TriangleMesh.xsp xsp/TriangleMesh.xsp

36
xs/src/Print.cpp Normal file
View File

@ -0,0 +1,36 @@
#include "Print.hpp"
namespace Slic3r {
bool
PrintState::started(PrintStep step) const
{
return this->_started.find(step) != this->_started.end();
}
bool
PrintState::done(PrintStep step) const
{
return this->_done.find(step) != this->_done.end();
}
void
PrintState::set_started(PrintStep step)
{
this->_started.insert(step);
}
void
PrintState::set_done(PrintStep step)
{
this->_done.insert(step);
}
void
PrintState::invalidate(PrintStep step)
{
this->_started.erase(step);
this->_done.erase(step);
}
}

29
xs/src/Print.hpp Normal file
View File

@ -0,0 +1,29 @@
#ifndef slic3r_Print_hpp_
#define slic3r_Print_hpp_
#include <set>
namespace Slic3r {
enum PrintStep {
psInitExtruders, psSlice, psPerimeters, prPrepareInfill,
psInfill, psSupportMaterial, psSkirt, psBrim,
};
class PrintState
{
private:
std::set<PrintStep> _started;
std::set<PrintStep> _done;
public:
bool started(PrintStep step) const;
bool done(PrintStep step) const;
void set_started(PrintStep step);
void set_done(PrintStep step);
void invalidate(PrintStep step);
};
}
#endif

41
xs/xsp/Print.xsp Normal file
View File

@ -0,0 +1,41 @@
%module{Slic3r::XS};
%{
#include <myinit.h>
#include "Print.hpp"
%}
%name{Slic3r::Print::State} class PrintState {
PrintState();
~PrintState();
bool started(PrintStep step) const;
bool done(PrintStep step) const;
void set_started(PrintStep step);
void set_done(PrintStep step);
void invalidate(PrintStep step);
%{
%}
};
%package{Slic3r::Print::State};
%{
IV
_constant()
ALIAS:
STEP_INIT_EXTRUDERS = psInitExtruders
STEP_SLICE = psSlice
STEP_PERIMETERS = psPerimeters
STEP_PREPARE_INFILL = prPrepareInfill
STEP_INFILL = psInfill
STEP_SUPPORTMATERIAL = psSupportMaterial
STEP_SKIRT = psSkirt
STEP_BRIM = psBrim
PROTOTYPE:
CODE:
RETVAL = ix;
OUTPUT: RETVAL
%}

View File

@ -12,10 +12,12 @@ ExPolygonCollection* O_OBJECT
ExtrusionEntityCollection* O_OBJECT ExtrusionEntityCollection* O_OBJECT
ExtrusionPath* O_OBJECT ExtrusionPath* O_OBJECT
ExtrusionLoop* O_OBJECT ExtrusionLoop* O_OBJECT
PrintState* O_OBJECT
Surface* O_OBJECT Surface* O_OBJECT
SurfaceCollection* O_OBJECT SurfaceCollection* O_OBJECT
ExtrusionRole T_UV ExtrusionRole T_UV
PrintStep T_UV
SurfaceType T_UV SurfaceType T_UV
ClipperLib::JoinType T_UV ClipperLib::JoinType T_UV
ClipperLib::PolyFillType T_UV ClipperLib::PolyFillType T_UV

View File

@ -18,6 +18,7 @@
%typemap{Lines}; %typemap{Lines};
%typemap{Polygons}; %typemap{Polygons};
%typemap{Polylines}; %typemap{Polylines};
%typemap{PrintState};
%typemap{ExPolygons}; %typemap{ExPolygons};
%typemap{Surfaces}; %typemap{Surfaces};
%typemap{Polygons*}; %typemap{Polygons*};
@ -35,3 +36,9 @@
$CVar = (ExtrusionRole)SvUV($PerlVar); $CVar = (ExtrusionRole)SvUV($PerlVar);
%}; %};
}; };
%typemap{PrintStep}{parsed}{
%cpp_type{PrintStep};
%precall_code{%
$CVar = (PrintStep)SvUV($PerlVar);
%};
};