Move Print object storage to C++. (along with its subobjects)

This commit is contained in:
Y. Sapir 2014-05-06 11:07:18 +03:00
parent 3df2488eca
commit 8da0bded1d
25 changed files with 1221 additions and 273 deletions

View file

@ -1,5 +1,4 @@
package Slic3r::Print::Object;
use Moo;
use List::Util qw(min max sum first);
use Slic3r::Flow ':roles';
@ -9,56 +8,38 @@ use Slic3r::Geometry::Clipper qw(diff diff_ex intersection intersection_ex union
use Slic3r::Print::State ':steps';
use Slic3r::Surface ':types';
has 'print' => (is => 'ro', weak_ref => 1, required => 1);
has 'model_object' => (is => 'ro', required => 1); # caller is responsible for holding the Model object
has 'region_volumes' => (is => 'rw', default => sub { [] }); # by region_id
has 'copies' => (is => 'ro'); # Slic3r::Point objects in scaled G-code coordinates
has 'config' => (is => 'ro', default => sub { Slic3r::Config::PrintObject->new });
has 'layer_height_ranges' => (is => 'rw', default => sub { [] }); # [ z_min, z_max, layer_height ]
has 'size' => (is => 'rw'); # XYZ in scaled coordinates
has '_copies_shift' => (is => 'rw'); # scaled coordinates to add to copies (to compensate for the alignment operated when creating the object but still preserving a coherent API for external callers)
has '_shifted_copies' => (is => 'rw'); # Slic3r::Point objects in scaled G-code coordinates in our coordinates
has 'layers' => (is => 'rw', default => sub { [] });
has 'support_layers' => (is => 'rw', default => sub { [] });
has 'fill_maker' => (is => 'lazy');
has '_state' => (is => 'ro', default => sub { Slic3r::Print::State->new });
sub BUILD {
my ($self) = @_;
# Compute the translation to be applied to our meshes so that we work with smaller coordinates
{
my $bb = $self->model_object->bounding_box;
# Translate meshes so that our toolpath generation algorithms work with smaller
# XY coordinates; this translation is an optimization and not strictly required.
# A cloned mesh will be aligned to 0 before slicing in _slice_region() since we
# don't assume it's already aligned and we don't alter the original position in model.
# We store the XY translation so that we can place copies correctly in the output G-code
# (copies are expressed in G-code coordinates and this translation is not publicly exposed).
$self->_copies_shift(Slic3r::Point->new_scale($bb->x_min, $bb->y_min));
$self->_trigger_copies;
# Scale the object size and store it
my $scaled_bb = $bb->clone;
$scaled_bb->scale(1 / &Slic3r::SCALING_FACTOR);
$self->size($scaled_bb->size);
}
}
sub _build_fill_maker {
# TODO: lazy
sub fill_maker {
my $self = shift;
return Slic3r::Fill->new(bounding_box => $self->bounding_box);
}
sub region_volumes {
my $self = shift;
return [ map $self->get_region_volumes($_), 0..($self->region_count - 1) ];
}
sub layers {
my $self = shift;
return [ map $self->get_layer($_), 0..($self->layer_count - 1) ];
}
sub support_layers {
my $self = shift;
return [ map $self->get_support_layer($_), 0..($self->support_layer_count - 1) ];
}
# TODO: translate to C++, then call it from constructor (see also
# Print->add_model_object)
sub _trigger_copies {
my $self = shift;
# TODO: should this mean point is 0,0?
return if !defined $self->_copies_shift;
# order copies with a nearest neighbor search and translate them by _copies_shift
$self->_shifted_copies([
$self->set_shifted_copies([
map {
my $c = $_->clone;
$c->translate(@{ $self->_copies_shift });
@ -73,28 +54,32 @@ sub _trigger_copies {
# in unscaled coordinates
sub add_copy {
my ($self, $x, $y) = @_;
push @{$self->copies}, Slic3r::Point->new_scale($x, $y);
my @copies = $self->copies;
push @copies, Slic3r::Point->new_scale($x, $y);
$self->set_copies(\@copies);
$self->_trigger_copies;
}
sub delete_last_copy {
my ($self) = @_;
pop @{$self->copies};
my @copies = $self->copies;
pop @copies;
$self->set_copies(\@copies);
$self->_trigger_copies;
}
sub delete_all_copies {
my ($self) = @_;
@{$self->copies} = ();
$self->set_copies([]);
$self->_trigger_copies;
}
# this is the *total* layer count
# this is the *total* layer count (including support layers)
# this value is not supposed to be compared with $layer->id
# since they have different semantics
sub layer_count {
sub total_layer_count {
my $self = shift;
return scalar @{ $self->layers } + scalar @{ $self->support_layers };
return $self->layer_count + $self->support_layer_count;
}
sub bounding_box {
@ -114,7 +99,7 @@ sub slice {
# init layers
{
@{$self->layers} = ();
$self->clear_layers;
# make layers taking custom heights into account
my $print_z = my $slice_z = my $height = my $id = 0;
@ -167,16 +152,10 @@ sub slice {
### Slic3r::debugf "Layer %d: height = %s; slice_z = %s; print_z = %s\n", $id, $height, $slice_z, $print_z;
push @{$self->layers}, Slic3r::Layer->new(
object => $self,
id => $id,
height => $height,
print_z => $print_z,
slice_z => $slice_z,
);
$self->add_layer($id, $height, $print_z, $slice_z);
if (@{$self->layers} >= 2) {
$self->layers->[-2]->upper_layer($self->layers->[-1]);
$self->layers->[-1]->lower_layer($self->layers->[-2]);
$self->layers->[-2]->set_upper_layer($self->layers->[-1]);
$self->layers->[-1]->set_lower_layer($self->layers->[-2]);
}
$id++;
@ -194,7 +173,7 @@ sub slice {
my @z = map $_->slice_z, @{$self->layers};
# slice all non-modifier volumes
for my $region_id (0..$#{$self->region_volumes}) {
for my $region_id (0..($self->region_count - 1)) {
my $expolygons_by_layer = $self->_slice_region($region_id, \@z, 0);
for my $layer_id (0..$#$expolygons_by_layer) {
my $layerm = $self->layers->[$layer_id]->regions->[$region_id];
@ -209,12 +188,12 @@ sub slice {
}
# then slice all modifier volumes
if (@{$self->region_volumes} > 1) {
for my $region_id (0..$#{$self->region_volumes}) {
if ($self->region_count > 1) {
for my $region_id (0..$self->region_count) {
my $expolygons_by_layer = $self->_slice_region($region_id, \@z, 1);
# loop through the other regions and 'steal' the slices belonging to this one
for my $other_region_id (0..$#{$self->region_volumes}) {
for my $other_region_id (0..$self->region_count) {
next if $other_region_id == $region_id;
for my $layer_id (0..$#$expolygons_by_layer) {
@ -248,7 +227,8 @@ sub slice {
}
# remove last layer(s) if empty
pop @{$self->layers} while @{$self->layers} && (!map @{$_->slices}, @{$self->layers->[-1]->regions});
$self->delete_layer($self->layer_count - 1)
while $self->layer_count && (!map @{$_->slices}, @{$self->layers->[-1]->regions});
foreach my $layer (@{ $self->layers }) {
# merge all regions' slices to get islands
@ -257,7 +237,7 @@ sub slice {
# detect slicing errors
my $warning_thrown = 0;
for my $i (0 .. $#{$self->layers}) {
for my $i (0 .. ($self->layer_count - 1)) {
my $layer = $self->layers->[$i];
next unless $layer->slicing_errors;
if (!$warning_thrown) {
@ -270,11 +250,11 @@ sub slice {
# neighbor layers
Slic3r::debugf "Attempting to repair layer %d\n", $i;
foreach my $region_id (0 .. $#{$layer->regions}) {
foreach my $region_id (0 .. ($layer->region_count - 1)) {
my $layerm = $layer->region($region_id);
my (@upper_surfaces, @lower_surfaces);
for (my $j = $i+1; $j <= $#{$self->layers}; $j++) {
for (my $j = $i+1; $j < $self->layer_count; $j++) {
if (!$self->layers->[$j]->slicing_errors) {
@upper_surfaces = @{$self->layers->[$j]->region($region_id)->slices};
last;
@ -308,10 +288,11 @@ sub slice {
}
# remove empty layers from bottom
# TODO: array index of layers after raft_layers would be 0, not raft_layers?
my $first_object_layer_id = $self->config->raft_layers;
while (@{$self->layers} && !@{$self->layers->[$first_object_layer_id]->slices}) {
splice @{$self->layers}, $first_object_layer_id, 1;
for (my $i = $first_object_layer_id; $i <= $#{$self->layers}; $i++) {
$self->delete_layer($first_object_layer_id);
for (my $i = $first_object_layer_id; $i < $self->layer_count; $i++) {
$self->layers->[$i]->id($i);
}
}
@ -325,11 +306,11 @@ sub slice {
sub _slice_region {
my ($self, $region_id, $z, $modifier) = @_;
return [] if !defined $self->region_volumes->[$region_id];
return [] if !@{$self->get_region_volumes($region_id)};
# compose mesh
my $mesh;
foreach my $volume_id (@{$self->region_volumes->[$region_id]}) {
foreach my $volume_id (@{ $self->get_region_volumes($region_id) }) {
my $volume = $self->model_object->volumes->[$volume_id];
next if $volume->modifier && !$modifier;
next if !$volume->modifier && $modifier;
@ -369,7 +350,7 @@ sub make_perimeters {
my $region_perimeters = $region->config->perimeters;
if ($region->config->extra_perimeters && $region_perimeters > 0 && $region->config->fill_density > 0) {
for my $i (0 .. $#{$self->layers}-1) {
for my $i (0 .. ($self->layer_count - 2)) {
my $layerm = $self->layers->[$i]->regions->[$region_id];
my $upper_layerm = $self->layers->[$i+1]->regions->[$region_id];
my $perimeter_spacing = $layerm->flow(FLOW_ROLE_PERIMETER)->scaled_spacing;
@ -418,7 +399,7 @@ sub make_perimeters {
Slic3r::parallelize(
threads => $self->print->config->threads,
items => sub { 0 .. $#{$self->layers} },
items => sub { 0 .. ($self->layer_count - 1) },
thread_cb => sub {
my $q = shift;
while (defined (my $i = $q->dequeue)) {
@ -442,7 +423,7 @@ sub detect_surfaces_type {
Slic3r::debugf "Detecting solid surfaces...\n";
for my $region_id (0 .. ($self->print->regions_count-1)) {
for my $i (0 .. $#{$self->layers}) {
for my $i (0 .. ($self->layer_count - 1)) {
my $layerm = $self->layers->[$i]->regions->[$region_id];
# prepare a reusable subroutine to make surface differences
@ -570,7 +551,7 @@ sub clip_fill_surfaces {
my $additional_margin = scale 3*0;
my $overhangs = []; # arrayref of polygons
for my $layer_id (reverse 0..$#{$self->layers}) {
for my $layer_id (reverse 0..($self->layer_count - 1)) {
my $layer = $self->layers->[$layer_id];
my @layer_internal = (); # arrayref of Surface objects
my @new_internal = (); # arrayref of Surface objects
@ -619,11 +600,11 @@ sub clip_fill_surfaces {
sub bridge_over_infill {
my $self = shift;
for my $region_id (0..$#{$self->print->regions}) {
for my $region_id (0..($self->print->region_count - 1)) {
my $fill_density = $self->print->regions->[$region_id]->config->fill_density;
next if $fill_density == 100 || $fill_density == 0;
for my $layer_id (1..$#{$self->layers}) {
for my $layer_id (1..($self->layer_count - 1)) {
my $layer = $self->layers->[$layer_id];
my $layerm = $layer->regions->[$region_id];
my $lower_layer = $self->layers->[$layer_id-1];
@ -697,7 +678,7 @@ sub process_external_surfaces {
for my $region_id (0 .. ($self->print->regions_count-1)) {
$self->layers->[0]->regions->[$region_id]->process_external_surfaces(undef);
for my $i (1 .. $#{$self->layers}) {
for my $i (1 .. ($self->layer_count - 1)) {
$self->layers->[$i]->regions->[$region_id]->process_external_surfaces($self->layers->[$i-1]);
}
}
@ -709,7 +690,7 @@ sub discover_horizontal_shells {
Slic3r::debugf "==> DISCOVERING HORIZONTAL SHELLS\n";
for my $region_id (0 .. ($self->print->regions_count-1)) {
for (my $i = 0; $i <= $#{$self->layers}; $i++) {
for (my $i = 0; $i < $self->layer_count; $i++) {
my $layerm = $self->layers->[$i]->regions->[$region_id];
if ($layerm->config->solid_infill_every_layers && $layerm->config->fill_density > 0
@ -741,7 +722,7 @@ sub discover_horizontal_shells {
abs($n - $i) <= $solid_layers-1;
($type == S_TYPE_TOP) ? $n-- : $n++) {
next if $n < 0 || $n > $#{$self->layers};
next if $n < 0 || $n >= $self->layer_count;
Slic3r::debugf " looking for neighbors on layer %d...\n", $n;
my $neighbor_layerm = $self->layers->[$n]->regions->[$region_id];