2012-04-29 10:51:20 +00:00
package Slic3r::Print::Object ;
use Moo ;
2012-05-19 13:40:11 +00:00
use Slic3r::ExtrusionPath ':roles' ;
2013-01-02 18:40:48 +00:00
use Slic3r::Geometry qw( Z PI scale unscale deg2rad rad2deg scaled_epsilon ) ;
2012-04-29 10:51:20 +00:00
use Slic3r::Geometry::Clipper qw( diff_ex intersection_ex union_ex ) ;
2012-05-19 14:04:33 +00:00
use Slic3r::Surface ':types' ;
2012-04-29 10:51:20 +00:00
2012-09-22 17:04:36 +00:00
has 'print' = > ( is = > 'ro' , weak_ref = > 1 , required = > 1 ) ;
2012-04-30 12:56:01 +00:00
has 'input_file' = > ( is = > 'rw' , required = > 0 ) ;
2012-09-23 00:52:31 +00:00
has 'meshes' = > ( is = > 'rw' , default = > sub { [] } ) ; # by region_id
2012-08-25 18:14:01 +00:00
has 'size' = > ( is = > 'rw' , required = > 1 ) ;
2012-09-22 14:19:24 +00:00
has 'copies' = > ( is = > 'rw' , default = > sub { [ [ 0 , 0 ] ] } ) ;
2012-09-22 17:04:36 +00:00
has 'layers' = > ( is = > 'rw' , default = > sub { [] } ) ;
2012-04-29 10:51:20 +00:00
2013-01-01 22:28:48 +00:00
sub BUILD {
my $ self = shift ;
# make layers
while ( ! @ { $ self - > layers } || $ self - > layers - > [ - 1 ] - > slice_z < $ self - > size - > [ Z ] ) {
push @ { $ self - > layers } , Slic3r::Layer - > new (
object = > $ self ,
id = > $# { $ self - > layers } + 1 ,
) ;
}
}
2012-04-29 10:51:20 +00:00
sub layer_count {
my $ self = shift ;
return scalar @ { $ self - > layers } ;
}
2013-01-01 22:28:48 +00:00
sub get_layer_range {
2012-04-29 10:51:20 +00:00
my $ self = shift ;
2013-01-01 22:28:48 +00:00
my ( $ min_z , $ max_z ) = @ _ ;
2012-04-29 10:51:20 +00:00
2013-01-01 22:28:48 +00:00
my ( $ min_layer , $ max_layer ) = ( 0 , undef ) ;
for my $ layer ( @ { $ self - > layers } ) {
$ min_layer = $ layer - > id if $ layer - > slice_z <= $ min_z ;
if ( $ layer - > slice_z >= $ max_z ) {
$ max_layer = $ layer - > id ;
last ;
}
2012-04-29 10:51:20 +00:00
}
2013-01-01 22:28:48 +00:00
return ( $ min_layer , $ max_layer ) ;
2012-04-29 10:51:20 +00:00
}
2012-04-30 12:56:01 +00:00
sub slice {
my $ self = shift ;
2012-05-28 17:58:27 +00:00
my % params = @ _ ;
2012-04-30 12:56:01 +00:00
# process facets
2012-09-23 00:52:31 +00:00
for my $ region_id ( 0 .. $# { $ self - > meshes } ) {
my $ mesh = $ self - > meshes - > [ $ region_id ] ; # ignore undef meshes
2012-09-22 17:04:36 +00:00
2012-04-30 12:56:01 +00:00
my $ apply_lines = sub {
my $ lines = shift ;
foreach my $ layer_id ( keys %$ lines ) {
2013-01-01 22:28:48 +00:00
my $ layerm = $ self - > layers - > [ $ layer_id ] - > region ( $ region_id ) ;
2012-09-22 17:04:36 +00:00
push @ { $ layerm - > lines } , @ { $ lines - > { $ layer_id } } ;
2012-04-30 12:56:01 +00:00
}
} ;
Slic3r:: parallelize (
2012-09-22 17:04:36 +00:00
disable = > ( $# { $ mesh - > facets } < 500 ) , # don't parallelize when too few facets
items = > [ 0 .. $# { $ mesh - > facets } ] ,
2012-04-30 12:56:01 +00:00
thread_cb = > sub {
my $ q = shift ;
my $ result_lines = { } ;
while ( defined ( my $ facet_id = $ q - > dequeue ) ) {
2012-09-22 17:04:36 +00:00
my $ lines = $ mesh - > slice_facet ( $ self , $ facet_id ) ;
2012-04-30 12:56:01 +00:00
foreach my $ layer_id ( keys %$ lines ) {
$ result_lines - > { $ layer_id } || = [] ;
push @ { $ result_lines - > { $ layer_id } } , @ { $ lines - > { $ layer_id } } ;
}
}
return $ result_lines ;
} ,
collect_cb = > sub {
$ apply_lines - > ( $ _ [ 0 ] ) ;
} ,
no_threads_cb = > sub {
2012-09-22 17:04:36 +00:00
for ( 0 .. $# { $ mesh - > facets } ) {
my $ lines = $ mesh - > slice_facet ( $ self , $ _ ) ;
2012-04-30 12:56:01 +00:00
$ apply_lines - > ( $ lines ) ;
}
} ,
) ;
}
die "Invalid input file\n" if ! @ { $ self - > layers } ;
2012-05-28 17:58:27 +00:00
# free memory
2012-09-22 17:04:36 +00:00
$ self - > meshes ( undef ) unless $ params { keep_meshes } ;
2012-05-28 17:58:27 +00:00
2012-04-30 12:56:01 +00:00
# remove last layer if empty
2012-09-22 17:04:36 +00:00
# (we might have created it because of the $max_layer = ... + 1 code in TriangleMesh)
2012-09-23 00:52:31 +00:00
pop @ { $ self - > layers } if ! map @ { $ _ - > lines } , @ { $ self - > layers - > [ - 1 ] - > regions } ;
2012-04-30 12:56:01 +00:00
foreach my $ layer ( @ { $ self - > layers } ) {
2012-09-23 00:52:31 +00:00
# make sure all layers contain layer region objects for all regions
$ layer - > region ( $ _ ) for 0 .. ( $ self - > print - > regions_count - 1 ) ;
2012-09-22 17:38:25 +00:00
2012-04-30 12:56:01 +00:00
Slic3r:: debugf "Making surfaces for layer %d (slice z = %f):\n" ,
$ layer - > id , unscale $ layer - > slice_z if $ Slic3r:: debug ;
# layer currently has many lines representing intersections of
# model facets with the layer plane. there may also be lines
# that we need to ignore (for example, when two non-horizontal
# facets share a common edge on our plane, we get a single line;
# however that line has no meaning for our layer as it's enclosed
# inside a closed polyline)
# build surfaces from sparse lines
2012-09-23 00:52:31 +00:00
foreach my $ layerm ( @ { $ layer - > regions } ) {
2012-09-22 17:04:36 +00:00
my ( $ slicing_errors , $ loops ) = Slic3r::TriangleMesh:: make_loops ( $ layerm - > lines ) ;
$ layer - > slicing_errors ( 1 ) if $ slicing_errors ;
$ layerm - > make_surfaces ( $ loops ) ;
# free memory
$ layerm - > lines ( undef ) ;
}
2012-04-30 12:56:01 +00:00
2012-09-23 00:52:31 +00:00
# merge all regions' slices to get islands
2012-09-22 17:04:36 +00:00
$ layer - > make_slices ;
2012-04-30 12:56:01 +00:00
}
# detect slicing errors
my $ warning_thrown = 0 ;
for my $ i ( 0 .. $# { $ self - > layers } ) {
my $ layer = $ self - > layers - > [ $ i ] ;
next unless $ layer - > slicing_errors ;
if ( ! $ warning_thrown ) {
warn "The model has overlapping or self-intersecting facets. I tried to repair it, "
. "however you might want to check the results or repair the input file and retry.\n" ;
$ warning_thrown = 1 ;
}
# try to repair the layer surfaces by merging all contours and all holes from
# neighbor layers
Slic3r:: debugf "Attempting to repair layer %d\n" , $ i ;
2012-09-23 00:52:31 +00:00
foreach my $ region_id ( 0 .. $# { $ layer - > regions } ) {
my $ layerm = $ layer - > region ( $ region_id ) ;
2012-09-22 17:04:36 +00:00
my ( @ upper_surfaces , @ lower_surfaces ) ;
for ( my $ j = $ i + 1 ; $ j <= $# { $ self - > layers } ; $ j + + ) {
if ( ! $ self - > layers - > [ $ j ] - > slicing_errors ) {
2012-09-23 00:52:31 +00:00
@ upper_surfaces = @ { $ self - > layers - > [ $ j ] - > region ( $ region_id ) - > slices } ;
2012-09-22 17:04:36 +00:00
last ;
}
2012-04-30 12:56:01 +00:00
}
2012-09-22 17:04:36 +00:00
for ( my $ j = $ i - 1 ; $ j >= 0 ; $ j - - ) {
if ( ! $ self - > layers - > [ $ j ] - > slicing_errors ) {
2012-09-23 00:52:31 +00:00
@ lower_surfaces = @ { $ self - > layers - > [ $ j ] - > region ( $ region_id ) - > slices } ;
2012-09-22 17:04:36 +00:00
last ;
}
2012-04-30 12:56:01 +00:00
}
2012-09-22 17:04:36 +00:00
my $ union = union_ex ( [
map $ _ - > expolygon - > contour , @ upper_surfaces , @ lower_surfaces ,
] ) ;
my $ diff = diff_ex (
[ map @$ _ , @$ union ] ,
[ map $ _ - > expolygon - > holes , @ upper_surfaces , @ lower_surfaces , ] ,
) ;
@ { $ layerm - > slices } = map Slic3r::Surface - > new
( expolygon = > $ _ , surface_type = > S_TYPE_INTERNAL ) ,
@$ diff ;
2012-04-30 12:56:01 +00:00
}
2012-09-22 17:04:36 +00:00
2012-09-23 00:52:31 +00:00
# update layer slices after repairing the single regions
2012-09-22 17:04:36 +00:00
$ layer - > make_slices ;
2012-04-30 12:56:01 +00:00
}
# remove empty layers from bottom
2013-01-28 13:12:01 +00:00
my $ first_object_layer_id = $ Slic3r:: Config - > raft_layers ;
while ( @ { $ self - > layers } && ! @ { $ self - > layers - > [ $ first_object_layer_id ] - > slices } && ! map @ { $ _ - > thin_walls } , @ { $ self - > layers - > [ $ first_object_layer_id ] - > regions } ) {
splice @ { $ self - > layers } , $ first_object_layer_id , 1 ;
for ( my $ i = $ first_object_layer_id ; $ i <= $# { $ self - > layers } ; $ i + + ) {
2012-04-30 12:56:01 +00:00
$ self - > layers - > [ $ i ] - > id ( $ i ) ;
}
}
warn "No layers were detected. You might want to repair your STL file and retry.\n"
if ! @ { $ self - > layers } ;
}
2012-05-05 14:36:10 +00:00
sub make_perimeters {
my $ self = shift ;
# compare each layer to the one below, and mark those slices needing
# one additional inner perimeter, like the top of domed objects-
2012-06-06 15:29:12 +00:00
# this algorithm makes sure that almost one perimeter is overlapping
2012-07-27 19:13:03 +00:00
if ( $ Slic3r:: Config - > extra_perimeters && $ Slic3r:: Config - > perimeters > 0 ) {
2012-09-23 00:52:31 +00:00
for my $ region_id ( 0 .. ( $ self - > print - > regions_count - 1 ) ) {
2012-09-22 17:04:36 +00:00
for my $ layer_id ( 0 .. $ self - > layer_count - 2 ) {
2012-09-23 01:03:08 +00:00
my $ layerm = $ self - > layers - > [ $ layer_id ] - > regions - > [ $ region_id ] ;
my $ upper_layerm = $ self - > layers - > [ $ layer_id + 1 ] - > regions - > [ $ region_id ] ;
my $ perimeter_flow = $ layerm - > perimeter_flow ;
2012-09-22 17:04:36 +00:00
2012-09-23 01:03:08 +00:00
my $ overlap = $ perimeter_flow - > spacing ; # one perimeter
2012-09-22 17:04:36 +00:00
# compute polygons representing the thickness of the first external perimeter of
# the upper layer slices
my $ upper = diff_ex (
2012-09-23 01:03:08 +00:00
[ map @$ _ , map $ _ - > expolygon - > offset_ex ( + 0.5 * $ perimeter_flow - > scaled_spacing ) , @ { $ upper_layerm - > slices } ] ,
[ map @$ _ , map $ _ - > expolygon - > offset_ex ( - scale ( $ overlap ) + ( 0.5 * $ perimeter_flow - > scaled_spacing ) ) , @ { $ upper_layerm - > slices } ] ,
2012-06-23 15:10:30 +00:00
) ;
2012-09-22 17:04:36 +00:00
next if ! @$ upper ;
# we need to limit our detection to the areas which would actually benefit from
# more perimeters. so, let's compute the area we want to ignore
my $ ignore = [] ;
{
my $ diff = diff_ex (
2012-09-23 01:03:08 +00:00
[ map @$ _ , map $ _ - > expolygon - > offset_ex ( - ( $ Slic3r:: Config - > perimeters - 0.5 ) * $ perimeter_flow - > scaled_spacing ) , @ { $ layerm - > slices } ] ,
2012-09-22 17:04:36 +00:00
[ map @ { $ _ - > expolygon } , @ { $ upper_layerm - > slices } ] ,
) ;
2012-09-23 01:03:08 +00:00
$ ignore = [ map @$ _ , map $ _ - > offset_ex ( $ perimeter_flow - > scaled_spacing ) , @$ diff ] ;
2012-09-22 17:04:36 +00:00
}
foreach my $ slice ( @ { $ layerm - > slices } ) {
my $ hypothetical_perimeter_num = $ Slic3r:: Config - > perimeters + 1 ;
CYCLE: while ( 1 ) {
# compute polygons representing the thickness of the hypotetical new internal perimeter
# of our slice
my $ hypothetical_perimeter ;
{
2012-10-22 11:11:43 +00:00
my $ outer = [ map @$ _ , $ slice - > expolygon - > offset_ex ( - ( $ hypothetical_perimeter_num - 1.5 ) * $ perimeter_flow - > scaled_spacing - scaled_epsilon ) ] ;
2012-09-22 17:04:36 +00:00
last CYCLE if ! @$ outer ;
2012-09-23 01:03:08 +00:00
my $ inner = [ map @$ _ , $ slice - > expolygon - > offset_ex ( - ( $ hypothetical_perimeter_num - 0.5 ) * $ perimeter_flow - > scaled_spacing ) ] ;
2012-09-22 17:04:36 +00:00
last CYCLE if ! @$ inner ;
$ hypothetical_perimeter = diff_ex ( $ outer , $ inner ) ;
}
last CYCLE if ! @$ hypothetical_perimeter ;
my $ intersection = intersection_ex ( [ map @$ _ , @$ upper ] , [ map @$ _ , @$ hypothetical_perimeter ] ) ;
$ intersection = diff_ex ( [ map @$ _ , @$ intersection ] , $ ignore ) if @$ ignore ;
last CYCLE if ! @ { $ intersection } ;
Slic3r:: debugf " adding one more perimeter at layer %d\n" , $ layer_id ;
$ slice - > additional_inner_perimeters ( ( $ slice - > additional_inner_perimeters || 0 ) + 1 ) ;
$ hypothetical_perimeter_num + + ;
2012-06-23 15:10:30 +00:00
}
2012-05-05 14:36:10 +00:00
}
}
}
}
2013-01-31 14:44:55 +00:00
Slic3r:: parallelize (
items = > sub { 0 .. ( $ self - > layer_count - 1 ) } ,
thread_cb = > sub {
my $ q = shift ;
$ Slic3r:: Geometry:: Clipper:: clipper = Math::Clipper - > new ;
my $ result = { } ;
while ( defined ( my $ layer_id = $ q - > dequeue ) ) {
my $ layer = $ self - > layers - > [ $ layer_id ] ;
$ layer - > make_perimeters ;
$ result - > { $ layer_id } || = { } ;
foreach my $ region_id ( 0 .. $# { $ layer - > regions } ) {
my $ layerm = $ layer - > regions - > [ $ region_id ] ;
$ result - > { $ layer_id } { $ region_id } = {
perimeters = > $ layerm - > perimeters ,
fill_surfaces = > $ layerm - > fill_surfaces ,
thin_fills = > $ layerm - > thin_fills ,
} ;
}
}
return $ result ;
} ,
collect_cb = > sub {
my $ result = shift ;
foreach my $ layer_id ( keys %$ result ) {
foreach my $ region_id ( keys % { $ result - > { $ layer_id } } ) {
$ self - > layers - > [ $ layer_id ] - > regions - > [ $ region_id ] - > $ _ ( $ result - > { $ layer_id } { $ region_id } { $ _ } )
for qw( perimeters fill_surfaces thin_fills ) ;
}
}
} ,
no_threads_cb = > sub {
$ _ - > make_perimeters for @ { $ self - > layers } ;
} ,
) ;
2012-05-05 14:36:10 +00:00
}
2012-04-29 10:51:20 +00:00
sub detect_surfaces_type {
my $ self = shift ;
Slic3r:: debugf "Detecting solid surfaces...\n" ;
# prepare a reusable subroutine to make surface differences
my $ surface_difference = sub {
2012-09-22 17:04:36 +00:00
my ( $ subject_surfaces , $ clip_surfaces , $ result_type , $ layerm ) = @ _ ;
2012-04-29 10:51:20 +00:00
my $ expolygons = diff_ex (
[ map { ref $ _ eq 'ARRAY' ? $ _ : ref $ _ eq 'Slic3r::ExPolygon' ? @$ _ : $ _ - > p } @$ subject_surfaces ] ,
[ map { ref $ _ eq 'ARRAY' ? $ _ : ref $ _ eq 'Slic3r::ExPolygon' ? @$ _ : $ _ - > p } @$ clip_surfaces ] ,
1 ,
) ;
2012-09-22 17:04:36 +00:00
return grep $ _ - > contour - > is_printable ( $ layerm - > flow - > width ) ,
2012-04-29 10:51:20 +00:00
map Slic3r::Surface - > new ( expolygon = > $ _ , surface_type = > $ result_type ) ,
@$ expolygons ;
} ;
2012-09-23 00:52:31 +00:00
for my $ region_id ( 0 .. ( $ self - > print - > regions_count - 1 ) ) {
2012-09-22 17:04:36 +00:00
for ( my $ i = 0 ; $ i < $ self - > layer_count ; $ i + + ) {
2012-09-23 00:52:31 +00:00
my $ layerm = $ self - > layers - > [ $ i ] - > regions - > [ $ region_id ] ;
2012-09-22 17:04:36 +00:00
2012-09-23 00:52:31 +00:00
# comparison happens against the *full* slices (considering all regions)
2012-09-22 17:04:36 +00:00
my $ upper_layer = $ self - > layers - > [ $ i + 1 ] ;
my $ lower_layer = $ i > 0 ? $ self - > layers - > [ $ i - 1 ] : undef ;
my ( @ bottom , @ top , @ internal ) = ( ) ;
# find top surfaces (difference between current surfaces
# of current layer and upper one)
if ( $ upper_layer ) {
@ top = $ surface_difference - > ( $ layerm - > slices , $ upper_layer - > slices , S_TYPE_TOP , $ layerm ) ;
} else {
# if no upper layer, all surfaces of this one are solid
@ top = @ { $ layerm - > slices } ;
$ _ - > surface_type ( S_TYPE_TOP ) for @ top ;
}
# find bottom surfaces (difference between current surfaces
# of current layer and lower one)
if ( $ lower_layer ) {
@ bottom = $ surface_difference - > ( $ layerm - > slices , $ lower_layer - > slices , S_TYPE_BOTTOM , $ layerm ) ;
} else {
# if no lower layer, all surfaces of this one are solid
@ bottom = @ { $ layerm - > slices } ;
$ _ - > surface_type ( S_TYPE_BOTTOM ) for @ bottom ;
}
# now, if the object contained a thin membrane, we could have overlapping bottom
# and top surfaces; let's do an intersection to discover them and consider them
# as bottom surfaces (to allow for bridge detection)
if ( @ top && @ bottom ) {
my $ overlapping = intersection_ex ( [ map $ _ - > p , @ top ] , [ map $ _ - > p , @ bottom ] ) ;
Slic3r:: debugf " layer %d contains %d membrane(s)\n" , $ layerm - > id , scalar ( @$ overlapping ) ;
@ top = $ surface_difference - > ( [ @ top ] , $ overlapping , S_TYPE_TOP , $ layerm ) ;
}
# find internal surfaces (difference between top/bottom surfaces and others)
@ internal = $ surface_difference - > ( $ layerm - > slices , [ @ top , @ bottom ] , S_TYPE_INTERNAL , $ layerm ) ;
# save surfaces to layer
@ { $ layerm - > slices } = ( @ bottom , @ top , @ internal ) ;
Slic3r:: debugf " layer %d has %d bottom, %d top and %d internal surfaces\n" ,
$ layerm - > id , scalar ( @ bottom ) , scalar ( @ top ) , scalar ( @ internal ) ;
2012-04-29 10:51:20 +00:00
}
2012-09-22 17:04:36 +00:00
# clip surfaces to the fill boundaries
foreach my $ layer ( @ { $ self - > layers } ) {
2012-09-23 00:52:31 +00:00
my $ layerm = $ layer - > regions - > [ $ region_id ] ;
2012-12-22 22:57:39 +00:00
my $ fill_boundaries = [ map @$ _ , @ { $ layerm - > fill_surfaces } ] ;
@ { $ layerm - > fill_surfaces } = ( ) ;
2012-09-22 17:04:36 +00:00
foreach my $ surface ( @ { $ layerm - > slices } ) {
my $ intersection = intersection_ex (
[ $ surface - > p ] ,
$ fill_boundaries ,
) ;
2012-12-22 22:57:39 +00:00
push @ { $ layerm - > fill_surfaces } , map Slic3r::Surface - > new
2012-09-22 17:04:36 +00:00
( expolygon = > $ _ , surface_type = > $ surface - > surface_type ) ,
@$ intersection ;
}
2012-04-29 10:51:20 +00:00
}
}
}
sub discover_horizontal_shells {
my $ self = shift ;
Slic3r:: debugf "==> DISCOVERING HORIZONTAL SHELLS\n" ;
2012-09-23 01:03:08 +00:00
my $ area_threshold = $ Slic3r:: flow - > scaled_spacing ** 2 ;
2012-05-01 16:51:47 +00:00
2012-09-23 00:52:31 +00:00
for my $ region_id ( 0 .. ( $ self - > print - > regions_count - 1 ) ) {
2012-09-22 17:04:36 +00:00
for ( my $ i = 0 ; $ i < $ self - > layer_count ; $ i + + ) {
2012-09-23 00:52:31 +00:00
my $ layerm = $ self - > layers - > [ $ i ] - > regions - > [ $ region_id ] ;
2012-09-28 13:46:29 +00:00
if ( $ Slic3r:: Config - > solid_infill_every_layers && ( $ i % $ Slic3r:: Config - > solid_infill_every_layers ) == 0 ) {
$ _ - > surface_type ( S_TYPE_INTERNALSOLID )
for grep $ _ - > surface_type == S_TYPE_INTERNAL , @ { $ layerm - > fill_surfaces } ;
}
2012-09-22 17:04:36 +00:00
foreach my $ type ( S_TYPE_TOP , S_TYPE_BOTTOM ) {
2012-12-21 19:25:48 +00:00
# find slices of current type for current layer
my @ surfaces = grep $ _ - > surface_type == $ type , @ { $ layerm - > slices } or next ;
2012-09-22 17:04:36 +00:00
my $ surfaces_p = [ map $ _ - > p , @ surfaces ] ;
Slic3r:: debugf "Layer %d has %d surfaces of type '%s'\n" ,
$ i , scalar ( @ surfaces ) , ( $ type == S_TYPE_TOP ? 'top' : 'bottom' ) ;
2012-04-29 10:51:20 +00:00
2012-10-28 11:52:44 +00:00
my $ solid_layers = ( $ type == S_TYPE_TOP )
? $ Slic3r:: Config - > top_solid_layers
: $ Slic3r:: Config - > bottom_solid_layers ;
2012-09-22 17:04:36 +00:00
for ( my $ n = $ type == S_TYPE_TOP ? $ i - 1 : $ i + 1 ;
2012-10-25 10:21:04 +00:00
abs ( $ n - $ i ) <= $ solid_layers - 1 ;
2012-09-22 17:04:36 +00:00
$ type == S_TYPE_TOP ? $ n - - : $ n + + ) {
next if $ n < 0 || $ n >= $ self - > layer_count ;
Slic3r:: debugf " looking for neighbors on layer %d...\n" , $ n ;
2012-09-23 00:52:31 +00:00
my @ neighbor_fill_surfaces = @ { $ self - > layers - > [ $ n ] - > regions - > [ $ region_id ] - > fill_surfaces } ;
2012-09-22 17:04:36 +00:00
# find intersection between neighbor and current layer's surfaces
# intersections have contours and holes
my $ new_internal_solid = intersection_ex (
$ surfaces_p ,
2012-12-22 22:57:39 +00:00
[ map $ _ - > p , grep { $ _ - > surface_type == S_TYPE_INTERNAL || $ _ - > surface_type == S_TYPE_INTERNALSOLID } @ neighbor_fill_surfaces ] ,
2012-09-22 17:04:36 +00:00
undef , 1 ,
) ;
next if ! @$ new_internal_solid ;
# internal-solid are the union of the existing internal-solid surfaces
# and new ones
my $ internal_solid = union_ex ( [
( map $ _ - > p , grep $ _ - > surface_type == S_TYPE_INTERNALSOLID , @ neighbor_fill_surfaces ) ,
( map @$ _ , @$ new_internal_solid ) ,
] ) ;
# subtract intersections from layer surfaces to get resulting inner surfaces
my $ internal = diff_ex (
[ map $ _ - > p , grep $ _ - > surface_type == S_TYPE_INTERNAL , @ neighbor_fill_surfaces ] ,
[ map @$ _ , @$ internal_solid ] ,
2012-05-01 16:51:47 +00:00
1 ,
2012-04-29 10:51:20 +00:00
) ;
2012-09-22 17:04:36 +00:00
Slic3r:: debugf " %d internal-solid and %d internal surfaces found\n" ,
scalar ( @$ internal_solid ) , scalar ( @$ internal ) ;
# Note: due to floating point math we're going to get some very small
# polygons as $internal; they will be removed by removed_small_features()
# assign resulting inner surfaces to layer
2012-09-23 00:52:31 +00:00
my $ neighbor_fill_surfaces = $ self - > layers - > [ $ n ] - > regions - > [ $ region_id ] - > fill_surfaces ;
2012-09-22 17:04:36 +00:00
@$ neighbor_fill_surfaces = ( ) ;
2012-04-29 10:51:20 +00:00
push @$ neighbor_fill_surfaces , Slic3r::Surface - > new
2012-09-22 17:04:36 +00:00
( expolygon = > $ _ , surface_type = > S_TYPE_INTERNAL )
for @$ internal ;
# assign new internal-solid surfaces to layer
push @$ neighbor_fill_surfaces , Slic3r::Surface - > new
( expolygon = > $ _ , surface_type = > S_TYPE_INTERNALSOLID )
for @$ internal_solid ;
# assign top and bottom surfaces to layer
foreach my $ s ( Slic3r::Surface - > group ( grep { $ _ - > surface_type == S_TYPE_TOP || $ _ - > surface_type == S_TYPE_BOTTOM } @ neighbor_fill_surfaces ) ) {
my $ solid_surfaces = diff_ex (
[ map $ _ - > p , @$ s ] ,
[ map @$ _ , @$ internal_solid , @$ internal ] ,
1 ,
) ;
push @$ neighbor_fill_surfaces , Slic3r::Surface - > new
( expolygon = > $ _ , surface_type = > $ s - > [ 0 ] - > surface_type , bridge_angle = > $ s - > [ 0 ] - > bridge_angle )
for @$ solid_surfaces ;
}
2012-04-29 10:51:20 +00:00
}
}
2012-09-22 17:04:36 +00:00
@ { $ layerm - > fill_surfaces } = grep $ _ - > expolygon - > area > $ area_threshold , @ { $ layerm - > fill_surfaces } ;
2012-04-29 10:51:20 +00:00
}
2012-12-23 19:20:17 +00:00
for ( my $ i = 0 ; $ i < $ self - > layer_count ; $ i + + ) {
my $ layerm = $ self - > layers - > [ $ i ] - > regions - > [ $ region_id ] ;
# if hollow object is requested, remove internal surfaces
if ( $ Slic3r:: Config - > fill_density == 0 ) {
@ { $ layerm - > fill_surfaces } = grep $ _ - > surface_type != S_TYPE_INTERNAL , @ { $ layerm - > fill_surfaces } ;
}
}
2012-04-29 10:51:20 +00:00
}
}
# combine fill surfaces across layers
2012-07-22 18:48:38 +00:00
sub combine_infill {
2012-04-29 10:51:20 +00:00
my $ self = shift ;
2012-07-27 19:13:03 +00:00
return unless $ Slic3r:: Config - > infill_every_layers > 1 && $ Slic3r:: Config - > fill_density > 0 ;
2012-04-29 10:51:20 +00:00
2012-09-23 01:03:08 +00:00
my $ area_threshold = $ Slic3r:: flow - > scaled_spacing ** 2 ;
2012-05-01 16:51:47 +00:00
2012-09-23 00:52:31 +00:00
for my $ region_id ( 0 .. ( $ self - > print - > regions_count - 1 ) ) {
2013-01-15 05:18:31 +00:00
# start from top, skip lowest layer
for ( my $ i = $ self - > layer_count - 1 ; $ i > 0 ; $ i - - ) {
2012-09-23 00:52:31 +00:00
my $ layerm = $ self - > layers - > [ $ i ] - > regions - > [ $ region_id ] ;
2012-04-29 10:51:20 +00:00
2012-09-22 17:04:36 +00:00
# skip layer if no internal fill surfaces
next if ! grep $ _ - > surface_type == S_TYPE_INTERNAL , @ { $ layerm - > fill_surfaces } ;
2012-04-29 10:51:20 +00:00
2012-09-22 17:04:36 +00:00
# for each possible depth, look for intersections with the lower layer
# we do this from the greater depth to the smaller
for ( my $ d = $ Slic3r:: Config - > infill_every_layers - 1 ; $ d >= 1 ; $ d - - ) {
2012-10-28 13:23:47 +00:00
next if ( $ i - $ d ) <= 0 ; # do not combine infill for bottom layer
2013-01-01 22:28:48 +00:00
my $ lower_layerm = $ self - > layers - > [ $ i - 1 ] - > regions - > [ $ region_id ] ;
2012-09-22 17:04:36 +00:00
# select surfaces of the lower layer having the depth we're looking for
my @ lower_surfaces = grep $ _ - > depth_layers == $ d && $ _ - > surface_type == S_TYPE_INTERNAL ,
@ { $ lower_layerm - > fill_surfaces } ;
next if ! @ lower_surfaces ;
# calculate intersection between our surfaces and theirs
my $ intersection = intersection_ex (
[ map $ _ - > p , grep $ _ - > depth_layers <= $ d , @ lower_surfaces ] ,
[ map $ _ - > p , grep $ _ - > surface_type == S_TYPE_INTERNAL , @ { $ layerm - > fill_surfaces } ] ,
undef , 1 ,
) ;
# purge intersections, skip tiny regions
@$ intersection = grep $ _ - > area > $ area_threshold , @$ intersection ;
next if ! @$ intersection ;
2012-04-29 10:51:20 +00:00
2012-09-22 17:04:36 +00:00
# new fill surfaces of the current layer are:
# - any non-internal surface
# - intersections found (with a $d + 1 depth)
# - any internal surface not belonging to the intersection (with its original depth)
{
my @ new_surfaces = ( ) ;
push @ new_surfaces , grep $ _ - > surface_type != S_TYPE_INTERNAL , @ { $ layerm - > fill_surfaces } ;
2012-04-29 10:51:20 +00:00
push @ new_surfaces , map Slic3r::Surface - > new
2012-09-22 17:04:36 +00:00
( expolygon = > $ _ , surface_type = > S_TYPE_INTERNAL , depth_layers = > $ d + 1 ) , @$ intersection ;
foreach my $ depth ( reverse $ d .. $ Slic3r:: Config - > infill_every_layers ) {
push @ new_surfaces , map Slic3r::Surface - > new
( expolygon = > $ _ , surface_type = > S_TYPE_INTERNAL , depth_layers = > $ depth ) ,
# difference between our internal layers with depth == $depth
# and the intersection found
@ { diff_ex (
[
map $ _ - > p , grep $ _ - > surface_type == S_TYPE_INTERNAL && $ _ - > depth_layers == $ depth ,
@ { $ layerm - > fill_surfaces } ,
] ,
[ map @$ _ , @$ intersection ] ,
1 ,
) } ;
}
@ { $ layerm - > fill_surfaces } = @ new_surfaces ;
2012-04-29 10:51:20 +00:00
}
2012-09-22 17:04:36 +00:00
# now we remove the intersections from lower layer
{
my @ new_surfaces = ( ) ;
push @ new_surfaces , grep $ _ - > surface_type != S_TYPE_INTERNAL , @ { $ lower_layerm - > fill_surfaces } ;
2013-01-15 05:18:31 +00:00
# offset for the two different flow spacings
$ intersection = [ map $ _ - > offset_ex (
2013-01-16 06:13:11 +00:00
$ lower_layerm - > infill_flow - > scaled_spacing / 2
+ $ layerm - > infill_flow - > scaled_spacing / 2
2013-01-15 05:18:31 +00:00
) , @$ intersection ] ;
2012-09-22 17:04:36 +00:00
foreach my $ depth ( 1 .. $ Slic3r:: Config - > infill_every_layers ) {
push @ new_surfaces , map Slic3r::Surface - > new
( expolygon = > $ _ , surface_type = > S_TYPE_INTERNAL , depth_layers = > $ depth ) ,
# difference between internal layers with depth == $depth
# and the intersection found
@ { diff_ex (
[
map $ _ - > p , grep $ _ - > surface_type == S_TYPE_INTERNAL && $ _ - > depth_layers == $ depth ,
@ { $ lower_layerm - > fill_surfaces } ,
] ,
[ map @$ _ , @$ intersection ] ,
1 ,
) } ;
}
@ { $ lower_layerm - > fill_surfaces } = @ new_surfaces ;
2012-04-29 10:51:20 +00:00
}
}
}
}
}
sub generate_support_material {
my $ self = shift ;
2013-01-02 18:40:48 +00:00
my $ threshold_rad = $ Slic3r:: Config - > support_material_threshold
? deg2rad ( $ Slic3r:: Config - > support_material_threshold + 1 ) # +1 makes the threshold inclusive
: PI /2 - atan2($self->layers->[1]->regions->[0]->perimeter_flow->width/ $ Slic3r:: Config - > layer_height / 2 , 1 ) ;
Slic3r:: debugf "Threshold angle = %d°\n" , rad2deg ( $ threshold_rad ) ;
2012-09-23 00:40:25 +00:00
my $ flow = $ self - > print - > support_material_flow ;
2012-07-27 19:13:03 +00:00
my $ overhang_width = $ threshold_rad == 0 ? undef : scale $ Slic3r:: Config - > layer_height * ( ( cos $ threshold_rad ) / ( sin $ threshold_rad ) ) ;
2012-09-23 01:03:08 +00:00
my $ distance_from_object = 1.5 * $ flow - > scaled_width ;
2012-11-23 16:15:52 +00:00
my $ pattern_spacing = ( $ Slic3r:: Config - > support_material_spacing > $ flow - > spacing )
? $ Slic3r:: Config - > support_material_spacing
: $ flow - > spacing ;
2012-06-21 09:51:24 +00:00
# determine support regions in each layer (for upper layers)
Slic3r:: debugf "Detecting regions\n" ;
2012-10-28 15:59:20 +00:00
my % layers = ( ) ; # this represents the areas of each layer having to support upper layers (excluding interfaces)
2013-02-03 16:23:50 +00:00
my % layers_interfaces = ( ) ; # this represents the areas of each layer to be filled with interface pattern, excluding the contact areas which are stored separately
my % layers_contact_areas = ( ) ; # this represents the areas of each layer having an overhang in the immediately upper layer
2012-04-29 10:51:20 +00:00
{
2012-06-21 09:51:24 +00:00
my @ current_support_regions = ( ) ; # expolygons we've started to support (i.e. below the empty interface layers)
2013-02-03 16:23:50 +00:00
my @ upper_layers_overhangs = ( map [] , 1 .. $ Slic3r:: Config - > support_material_interface_layers ) ;
2012-04-29 10:51:20 +00:00
for my $ i ( reverse 0 .. $# { $ self - > layers } ) {
2013-02-02 15:16:43 +00:00
next unless $ Slic3r:: Config - > support_material || ( $ i <= $ Slic3r:: Config - > raft_layers ) ; # <= because we need to start from the first non-raft layer
2012-04-29 10:51:20 +00:00
my $ layer = $ self - > layers - > [ $ i ] ;
2012-06-24 12:39:35 +00:00
my $ lower_layer = $ i > 0 ? $ self - > layers - > [ $ i - 1 ] : undef ;
2012-06-21 09:51:24 +00:00
2013-01-17 10:59:14 +00:00
my @ current_layer_offsetted_slices = map $ _ - > offset_ex ( $ distance_from_object ) , @ { $ layer - > slices } ;
2013-02-03 16:23:50 +00:00
# $upper_layers_overhangs[-1] contains the overhangs of the upper layer, regardless of any interface layers
# $upper_layers_overhangs[0] contains the overhangs of the first upper layer above the interface layers
# we only consider the overhangs of the upper layer to define contact areas of the current one
$ layers_contact_areas { $ i } = diff_ex (
[ map @$ _ , @ { $ upper_layers_overhangs [ - 1 ] || [] } ] ,
2013-01-17 10:59:14 +00:00
[ map @$ _ , @ current_layer_offsetted_slices ] ,
) ;
2013-02-03 16:23:50 +00:00
$ _ - > simplify ( $ flow - > scaled_spacing ) for @ { $ layers_contact_areas { $ i } } ;
2012-10-28 15:59:20 +00:00
2013-02-03 16:23:50 +00:00
# to define interface regions of this layer we consider the overhangs of all the upper layers
# minus the first one
$ layers_interfaces { $ i } = diff_ex (
[ map @$ _ , map @$ _ , @ upper_layers_overhangs [ 0 .. $# upper_layers_overhangs - 1 ] ] ,
[
( map @$ _ , @ current_layer_offsetted_slices ) ,
( map @$ _ , @ { $ layers_contact_areas { $ i } } ) ,
] ,
) ;
$ _ - > simplify ( $ flow - > scaled_spacing ) for @ { $ layers_interfaces { $ i } } ;
2012-06-24 12:39:35 +00:00
2013-02-03 16:23:50 +00:00
# generate support material in current layer (for upper layers)
2012-06-21 09:51:24 +00:00
@ current_support_regions = @ { diff_ex (
2013-02-03 16:23:50 +00:00
[
( map @$ _ , @ current_support_regions ) ,
( map @$ _ , @ { $ upper_layers_overhangs [ - 1 ] || [] } ) , # only considering -1 instead of the whole array contents is just an optimization
] ,
2012-09-22 19:03:57 +00:00
[ map @$ _ , @ { $ layer - > slices } ] ,
2012-06-21 09:51:24 +00:00
) } ;
2013-02-03 16:23:50 +00:00
shift @ upper_layers_overhangs ;
2012-06-21 09:51:24 +00:00
2012-06-24 12:39:35 +00:00
$ layers { $ i } = diff_ex (
[ map @$ _ , @ current_support_regions ] ,
2012-10-28 15:59:20 +00:00
[
2013-01-17 10:59:14 +00:00
( map @$ _ , @ current_layer_offsetted_slices ) ,
2013-02-03 16:23:50 +00:00
( map @$ _ , @ { $ layers_contact_areas { $ i } } ) ,
2012-10-28 15:59:20 +00:00
( map @$ _ , @ { $ layers_interfaces { $ i } } ) ,
] ,
2012-06-24 12:39:35 +00:00
) ;
2013-01-17 10:59:14 +00:00
$ _ - > simplify ( $ flow - > scaled_spacing ) for @ { $ layers { $ i } } ;
2012-06-21 09:51:24 +00:00
2013-02-03 16:23:50 +00:00
# get layer overhangs and put them into queue for adding support inside lower layers;
2012-06-21 09:51:24 +00:00
# we need an angle threshold for this
my @ overhangs = ( ) ;
2012-06-24 12:39:35 +00:00
if ( $ lower_layer ) {
2012-06-23 21:54:39 +00:00
@ overhangs = map $ _ - > offset_ex ( 2 * $ overhang_width ) , @ { diff_ex (
2012-09-22 19:03:57 +00:00
[ map @$ _ , map $ _ - > offset_ex ( - $ overhang_width ) , @ { $ layer - > slices } ] ,
[ map @$ _ , @ { $ lower_layer - > slices } ] ,
2012-06-21 09:51:24 +00:00
1 ,
2012-04-29 10:51:20 +00:00
) } ;
}
2013-02-03 16:23:50 +00:00
push @ upper_layers_overhangs , [ @ overhangs ] ;
if ( $ Slic3r:: debug ) {
printf "Layer %d has %d generic support areas, %d normal interface areas, %d contact areas\n" ,
$ i , scalar ( @ { $ layers { $ i } } ) , scalar ( @ { $ layers_interfaces { $ i } } ) , scalar ( @ { $ layers_contact_areas { $ i } } ) ;
}
2012-04-29 10:51:20 +00:00
}
}
2012-06-24 12:39:35 +00:00
return if ! map @$ _ , values % layers ;
2012-04-29 10:51:20 +00:00
# generate paths for the pattern that we're going to use
2012-06-21 09:51:24 +00:00
Slic3r:: debugf "Generating patterns\n" ;
2013-02-03 16:23:50 +00:00
my $ support_patterns = [] ;
my $ support_interface_patterns = [] ;
2012-04-29 10:51:20 +00:00
{
2013-02-03 16:23:50 +00:00
# 0.5 ensures the paths don't get clipped externally when applying them to layers
my @ areas = map $ _ - > offset_ex ( - 0.5 * $ flow - > scaled_width ) ,
2012-06-24 12:39:35 +00:00
@ { union_ex ( [ map $ _ - > contour , map @$ _ , values % layers ] ) } ;
2012-04-29 10:51:20 +00:00
2013-02-01 23:14:45 +00:00
my $ pattern = $ Slic3r:: Config - > support_material_pattern ;
my @ angles = ( $ Slic3r:: Config - > support_material_angle ) ;
if ( $ pattern eq 'rectilinear-grid' ) {
$ pattern = 'rectilinear' ;
push @ angles , $ angles [ 0 ] + 90 ;
}
my $ filler = Slic3r::Fill - > filler ( $ pattern ) ;
2013-02-03 16:23:50 +00:00
my $ make_pattern = sub {
my ( $ expolygon , $ density ) = @ _ ;
my @ paths = $ filler - > fill_surface (
Slic3r::Surface - > new ( expolygon = > $ expolygon ) ,
density = > $ density ,
flow_spacing = > $ flow - > spacing ,
) ;
my $ params = shift @ paths ;
return map Slic3r::ExtrusionPath - > new (
polyline = > Slic3r::Polyline - > new ( @$ _ ) ,
role = > EXTR_ROLE_SUPPORTMATERIAL ,
height = > undef ,
flow_spacing = > $ params - > { flow_spacing } ,
) , @ paths ;
} ;
2013-02-01 23:14:45 +00:00
foreach my $ angle ( @ angles ) {
$ filler - > angle ( $ angle ) ;
2013-02-03 16:23:50 +00:00
{
my $ density = $ flow - > spacing / $ pattern_spacing ;
push @$ support_patterns , [ map $ make_pattern - > ( $ _ , $ density ) , @ areas ] ;
}
if ( $ Slic3r:: Config - > support_material_interface_layers > 0 ) {
# if pattern is not cross-hatched, rotate the interface pattern by 90° degrees
$ filler - > angle ( $ angle + 90 ) if @ angles == 1 ;
2012-04-29 10:51:20 +00:00
2013-02-03 16:23:50 +00:00
my $ spacing = $ Slic3r:: Config - > support_material_interface_spacing ;
my $ density = $ spacing == 0 ? 1 : $ flow - > spacing / $ spacing ;
push @$ support_interface_patterns , [ map $ make_pattern - > ( $ _ , $ density ) , @ areas ] ;
2012-04-29 10:51:20 +00:00
}
}
2012-06-21 09:51:24 +00:00
if ( 0 ) {
require "Slic3r/SVG.pm" ;
2012-11-01 10:34:53 +00:00
Slic3r::SVG:: output ( "support_$_.svg" ,
2012-06-21 09:51:24 +00:00
polylines = > [ map $ _ - > polyline , map @$ _ , $ support_patterns - > [ $ _ ] ] ,
2013-02-03 16:23:50 +00:00
red_polylines = > [ map $ _ - > polyline , map @$ _ , $ support_interface_patterns - > [ $ _ ] ] ,
polygons = > [ map @$ _ , @ areas ] ,
2012-06-23 20:58:12 +00:00
) for 0 .. $#$ support_patterns ;
2012-06-21 09:51:24 +00:00
}
2012-04-29 10:51:20 +00:00
}
# apply the pattern to layers
2012-06-21 09:51:24 +00:00
Slic3r:: debugf "Applying patterns\n" ;
2012-04-29 10:51:20 +00:00
{
my $ clip_pattern = sub {
2013-02-03 16:23:50 +00:00
my ( $ layer_id , $ expolygons , $ height , $ is_interface ) = @ _ ;
2012-04-29 10:51:20 +00:00
my @ paths = ( ) ;
foreach my $ expolygon ( @$ expolygons ) {
2012-07-20 12:39:07 +00:00
push @ paths ,
map $ _ - > pack ,
2012-09-23 00:40:25 +00:00
map {
2012-10-28 15:59:20 +00:00
$ _ - > height ( $ height ) ;
2013-02-03 16:23:50 +00:00
# useless line because this coderef isn't called for layer 0 anymore;
# let's keep it here just in case we want to make the base flange optional
# in the future
2012-09-23 00:40:25 +00:00
$ _ - > flow_spacing ( $ self - > print - > first_layer_support_material_flow - > spacing )
if $ layer_id == 0 ;
2013-02-03 16:23:50 +00:00
2012-09-23 00:40:25 +00:00
$ _ ;
}
2012-07-20 12:39:07 +00:00
map $ _ - > clip_with_expolygon ( $ expolygon ) ,
2013-02-01 22:45:46 +00:00
###map $_->clip_with_polygon($expolygon->bounding_box_polygon), # currently disabled as a workaround for Boost failing at being idempotent
2013-02-03 16:23:50 +00:00
( $ is_interface && @$ support_interface_patterns )
? @ { $ support_interface_patterns - > [ $ layer_id % @ $ support_interface_patterns ] }
: @ { $ support_patterns - > [ $ layer_id % @ $ support_patterns ] } ;
2012-04-29 10:51:20 +00:00
} ;
return @ paths ;
} ;
2012-12-20 17:47:40 +00:00
my % layer_paths = ( ) ;
2013-02-03 16:23:50 +00:00
my % layer_contact_paths = ( ) ;
2012-12-20 17:47:40 +00:00
my % layer_islands = ( ) ;
2012-10-28 15:59:20 +00:00
my $ process_layer = sub {
my ( $ layer_id ) = @ _ ;
my $ layer = $ self - > layers - > [ $ layer_id ] ;
2013-02-01 21:13:12 +00:00
2013-02-03 16:23:50 +00:00
my ( $ paths , $ contact_paths ) = ( [] , [] ) ;
my $ islands = union_ex ( [ map @$ _ , map @$ _ , $ layers { $ layer_id } , $ layers_contact_areas { $ layer_id } ] ) ;
2013-02-01 21:13:12 +00:00
# make a solid base on bottom layer
if ( $ layer_id == 0 ) {
my $ filler = Slic3r::Fill - > filler ( 'rectilinear' ) ;
$ filler - > angle ( $ Slic3r:: Config - > support_material_angle + 90 ) ;
foreach my $ expolygon ( @$ islands ) {
my @ paths = $ filler - > fill_surface (
Slic3r::Surface - > new ( expolygon = > $ expolygon ) ,
2013-02-02 14:37:09 +00:00
density = > 0.5 ,
2013-02-01 21:13:12 +00:00
flow_spacing = > $ self - > print - > first_layer_support_material_flow - > spacing ,
) ;
my $ params = shift @ paths ;
push @$ paths , map Slic3r::ExtrusionPath - > new (
polyline = > Slic3r::Polyline - > new ( @$ _ ) ,
role = > EXTR_ROLE_SUPPORTMATERIAL ,
height = > undef ,
flow_spacing = > $ params - > { flow_spacing } ,
) , @ paths ;
}
} else {
2013-02-03 16:23:50 +00:00
$ paths = [
$ clip_pattern - > ( $ layer_id , $ layers { $ layer_id } , $ layer - > height ) ,
$ clip_pattern - > ( $ layer_id , $ layers_interfaces { $ layer_id } , $ layer - > height , 1 ) ,
] ;
$ contact_paths = [ $ clip_pattern - > ( $ layer_id , $ layers_contact_areas { $ layer_id } , $ layer - > support_material_contact_height , 1 ) ] ;
2013-02-01 21:13:12 +00:00
}
2013-02-03 16:23:50 +00:00
return ( $ paths , $ contact_paths , $ islands ) ;
2012-10-28 15:59:20 +00:00
} ;
2012-04-29 10:51:20 +00:00
Slic3r:: parallelize (
items = > [ keys % layers ] ,
thread_cb = > sub {
my $ q = shift ;
2013-01-16 13:52:26 +00:00
$ Slic3r:: Geometry:: Clipper:: clipper = Math::Clipper - > new ;
2012-12-20 17:47:40 +00:00
my $ result = { } ;
2012-04-29 10:51:20 +00:00
while ( defined ( my $ layer_id = $ q - > dequeue ) ) {
2012-12-20 17:47:40 +00:00
$ result - > { $ layer_id } = [ $ process_layer - > ( $ layer_id ) ] ;
2012-04-29 10:51:20 +00:00
}
2012-12-20 17:47:40 +00:00
return $ result ;
2012-04-29 10:51:20 +00:00
} ,
collect_cb = > sub {
2012-12-20 17:47:40 +00:00
my $ result = shift ;
2013-02-03 16:23:50 +00:00
( $ layer_paths { $ _ } , $ layer_contact_paths { $ _ } , $ layer_islands { $ _ } ) = @ { $ result - > { $ _ } } for keys %$ result ;
2012-04-29 10:51:20 +00:00
} ,
no_threads_cb = > sub {
2013-02-03 16:23:50 +00:00
( $ layer_paths { $ _ } , $ layer_contact_paths { $ _ } , $ layer_islands { $ _ } ) = $ process_layer - > ( $ _ ) for keys % layers ;
2012-04-29 10:51:20 +00:00
} ,
) ;
foreach my $ layer_id ( keys % layer_paths ) {
my $ layer = $ self - > layers - > [ $ layer_id ] ;
2012-12-20 17:47:40 +00:00
$ layer - > support_islands ( $ layer_islands { $ layer_id } ) ;
2012-04-29 10:51:20 +00:00
$ layer - > support_fills ( Slic3r::ExtrusionPath::Collection - > new ) ;
2013-02-03 16:23:50 +00:00
$ layer - > support_contact_fills ( Slic3r::ExtrusionPath::Collection - > new ) ;
2012-04-29 10:51:20 +00:00
push @ { $ layer - > support_fills - > paths } , @ { $ layer_paths { $ layer_id } } ;
2013-02-03 16:23:50 +00:00
push @ { $ layer - > support_contact_fills - > paths } , @ { $ layer_contact_paths { $ layer_id } } ;
2012-04-29 10:51:20 +00:00
}
}
}
1 ;