@@ -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 } ) {
# apply size compensation
@@ -310,7 +290,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 ) {
@@ -323,11 +303,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 ;
@@ -377,11 +357,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 ;
@@ -421,7 +401,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 ;
@@ -471,7 +451,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 ) ) {
@@ -495,7 +475,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
@@ -623,7 +603,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
@@ -672,11 +652,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 ] ;
@@ -750,7 +730,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 ] ) ;
}
}
@@ -762,7 +742,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
@@ -794,7 +774,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 ] ;