mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-24 15:13:58 -06:00
Move Print object storage to C++. (along with its subobjects)
This commit is contained in:
parent
3df2488eca
commit
8da0bded1d
25 changed files with 1221 additions and 273 deletions
|
@ -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];
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue