2011-09-05 10:21:27 +00:00
package Slic3r::Fill::Rectilinear ;
2011-09-06 09:50:43 +00:00
use Moo ;
2011-09-05 10:21:27 +00:00
2011-10-06 11:43:32 +00:00
extends 'Slic3r::Fill::Base' ;
2012-09-12 13:22:43 +00:00
use Slic3r::Geometry qw( X1 Y1 X2 Y2 A B X Y scale unscale scaled_epsilon ) ;
2011-09-05 10:21:27 +00:00
2011-10-06 11:43:32 +00:00
sub fill_surface {
2011-09-05 10:21:27 +00:00
my $ self = shift ;
2011-10-06 11:43:32 +00:00
my ( $ surface , % params ) = @ _ ;
# rotate polygons so that we can work with vertical lines here
2012-04-09 20:04:57 +00:00
my $ expolygon = $ surface - > expolygon - > clone ;
2011-10-07 17:07:57 +00:00
my $ rotate_vector = $ self - > infill_direction ( $ surface ) ;
2011-11-13 17:14:02 +00:00
$ self - > rotate_points ( $ expolygon , $ rotate_vector ) ;
2011-10-06 11:43:32 +00:00
2012-08-24 16:59:23 +00:00
my ( $ expolygon_off ) = $ expolygon - > offset_ex ( scale $ params { flow_spacing } / 2 ) ;
2012-03-10 22:49:24 +00:00
return { } if ! $ expolygon_off ; # skip some very small polygons (which shouldn't arrive here)
2012-05-19 19:57:47 +00:00
my $ bounding_box = [ $ expolygon - > bounding_box ] ;
2011-12-04 15:24:46 +00:00
2011-12-17 18:52:34 +00:00
my $ min_spacing = scale $ params { flow_spacing } ;
2011-12-04 15:24:46 +00:00
my $ distance_between_lines = $ min_spacing / $ params { density } ;
my $ line_oscillation = $ distance_between_lines - $ min_spacing ;
2012-09-12 10:13:43 +00:00
my $ flow_spacing = $ params { flow_spacing } ;
2011-12-19 08:55:03 +00:00
if ( $ params { density } == 1 ) {
$ distance_between_lines = $ self - > adjust_solid_spacing (
width = > $ bounding_box - > [ X2 ] - $ bounding_box - > [ X1 ] ,
distance = > $ distance_between_lines ,
) ;
$ flow_spacing = unscale $ distance_between_lines ;
}
2011-12-17 19:29:06 +00:00
2012-10-30 13:21:59 +00:00
my $ overlap_distance = scale $ params { flow_spacing } * & Slic3r:: PERIMETER_INFILL_OVERLAP_OVER_SPACING ;
2011-10-06 11:43:32 +00:00
2011-10-06 13:24:21 +00:00
my $ x = $ bounding_box - > [ X1 ] ;
2011-11-14 09:31:07 +00:00
my $ is_line_pattern = $ self - > isa ( 'Slic3r::Fill::Line' ) ;
2012-04-09 09:04:32 +00:00
my @ vertical_lines = ( ) ;
2012-09-12 13:22:43 +00:00
for ( my $ i = 0 ; $ x <= $ bounding_box - > [ X2 ] + scaled_epsilon ; $ i + + ) {
2012-02-25 21:15:34 +00:00
my $ vertical_line = Slic3r::Line - > new ( [ $ x , $ bounding_box - > [ Y2 ] ] , [ $ x , $ bounding_box - > [ Y1 ] ] ) ;
2011-11-14 09:31:07 +00:00
if ( $ is_line_pattern && $ i % 2 ) {
2012-03-04 10:45:45 +00:00
$ vertical_line - > [ A ] [ X ] += $ line_oscillation ;
$ vertical_line - > [ B ] [ X ] -= $ line_oscillation ;
2011-11-14 09:31:07 +00:00
}
2012-04-09 09:04:32 +00:00
push @ vertical_lines , $ vertical_line ;
2011-12-04 15:24:46 +00:00
$ x += $ distance_between_lines ;
}
2012-08-24 16:59:23 +00:00
# clip paths against a slightly offsetted expolygon, so that the first and last paths
# are kept even if the expolygon has vertical sides
2012-04-09 09:04:32 +00:00
my @ paths = @ { Boost::Geometry::Utils:: polygon_linestring_intersection (
2012-09-12 13:22:43 +00:00
+ ( $ expolygon - > offset_ex ( scaled_epsilon ) ) [ 0 ] - > boost_polygon , # TODO: we should use all the resulting expolygons and clip the linestrings to a multipolygon object
2012-04-09 09:04:32 +00:00
Boost::Geometry::Utils:: linestring ( @ vertical_lines ) ,
) } ;
for ( @ paths ) {
$ _ - > [ 0 ] [ Y ] += $ overlap_distance ;
$ _ - > [ - 1 ] [ Y ] -= $ overlap_distance ;
}
2011-12-04 15:24:46 +00:00
# connect lines
2012-10-24 14:17:09 +00:00
unless ( $ params { dont_connect } ) {
2012-10-30 13:07:01 +00:00
my $ collection = Slic3r::Polyline::Collection - > new (
polylines = > [ map Slic3r::Polyline - > new ( @$ _ ) , @ paths ] ,
2011-12-04 15:24:46 +00:00
) ;
@ paths = ( ) ;
2012-09-12 13:22:43 +00:00
my $ tolerance = 10 * scaled_epsilon ;
2012-05-04 18:51:09 +00:00
my $ diagonal_distance = $ distance_between_lines * 5 ;
my $ can_connect = $ is_line_pattern
? sub {
( $ _ [ X ] >= ( $ distance_between_lines - $ line_oscillation ) - $ tolerance ) && ( $ _ [ X ] <= ( $ distance_between_lines + $ line_oscillation ) + $ tolerance )
2012-06-23 18:27:28 +00:00
&& $ _ [ Y ] <= $ diagonal_distance
2012-05-04 18:51:09 +00:00
}
2012-06-23 20:43:23 +00:00
: sub { abs ( $ _ [ X ] - $ distance_between_lines ) <= $ tolerance && $ _ [ Y ] <= $ diagonal_distance } ;
2011-12-04 15:24:46 +00:00
foreach my $ path ( $ collection - > shortest_path ) {
if ( @ paths ) {
2012-10-30 13:07:01 +00:00
my @ distance = map abs ( $ path - > [ 0 ] [ $ _ ] - $ paths [ - 1 ] [ - 1 ] [ $ _ ] ) , ( X , Y ) ;
2011-12-04 15:24:46 +00:00
# TODO: we should also check that both points are on a fill_boundary to avoid
# connecting paths on the boundaries of internal regions
2012-10-30 13:07:01 +00:00
if ( $ can_connect - > ( @ distance , $ paths [ - 1 ] [ - 1 ] , $ path - > [ 0 ] )
&& $ expolygon_off - > encloses_line ( Slic3r::Line - > new ( $ paths [ - 1 ] [ - 1 ] , $ path - > [ 0 ] ) , $ tolerance ) ) {
push @ { $ paths [ - 1 ] } , @$ path ;
2011-12-04 15:24:46 +00:00
next ;
}
}
2012-10-30 13:07:01 +00:00
push @ paths , $ path ;
2011-12-04 15:24:46 +00:00
}
2011-09-25 18:09:30 +00:00
}
2011-10-06 11:43:32 +00:00
# paths must be rotated back
$ self - > rotate_points_back ( \ @ paths , $ rotate_vector ) ;
2011-12-17 18:52:34 +00:00
return { flow_spacing = > $ flow_spacing } , @ paths ;
2011-09-05 10:21:27 +00:00
}
1 ;