2011-09-05 12:21:27 +02:00
package Slic3r::Fill::Rectilinear ;
2011-09-06 11:50:43 +02:00
use Moo ;
2011-09-05 12:21:27 +02:00
2011-10-06 13:43:32 +02:00
extends 'Slic3r::Fill::Base' ;
2012-09-12 15:22:43 +02:00
use Slic3r::Geometry qw(X1 Y1 X2 Y2 A B X Y scale unscale scaled_epsilon) ;
2011-09-05 12:21:27 +02:00
2011-10-06 13:43:32 +02:00
sub fill_surface {
2011-09-05 12:21:27 +02:00
my $self = shift ;
2011-10-06 13:43:32 +02:00
my ( $surface , %params ) = @_ ;
2011-09-05 12:21:27 +02:00
2011-10-06 13:43:32 +02:00
# rotate polygons so that we can work with vertical lines here
2012-04-09 22:04:57 +02:00
my $expolygon = $surface -> expolygon -> clone ;
2011-10-07 19:07:57 +02:00
my $rotate_vector = $self -> infill_direction ( $surface );
2011-11-13 18:14:02 +01:00
$self -> rotate_points ( $expolygon , $rotate_vector );
2011-10-06 15:24:21 +02:00
2012-08-24 18:59:23 +02:00
my ( $expolygon_off ) = $expolygon -> offset_ex ( scale $params { flow_spacing } / 2 );
2012-03-10 23:49:24 +01:00
return {} if ! $expolygon_off ; # skip some very small polygons (which shouldn't arrive here)
2012-05-19 21:57:47 +02:00
my $bounding_box = [ $expolygon -> bounding_box ];
2011-12-04 16:24:46 +01:00
2011-12-17 19:52:34 +01:00
my $min_spacing = scale $params { flow_spacing };
2011-12-04 16:24:46 +01:00
my $distance_between_lines = $min_spacing / $params { density };
my $line_oscillation = $distance_between_lines - $min_spacing ;
2012-09-12 12:13:43 +02:00
my $flow_spacing = $params { flow_spacing };
2012-11-16 18:10:09 +01:00
if ( $params { density } == 1 && ! $params { dont_adjust }) {
2011-12-19 09:55:03 +01:00
$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 20:29:06 +01:00
2012-10-30 14:21:59 +01:00
my $overlap_distance = scale $params { flow_spacing } * & Slic3r:: PERIMETER_INFILL_OVERLAP_OVER_SPACING ;
2011-10-06 13:43:32 +02:00
2011-10-06 15:24:21 +02:00
my $x = $bounding_box -> [ X1 ];
2011-11-14 10:31:07 +01:00
my $is_line_pattern = $self -> isa ( 'Slic3r::Fill::Line' );
2012-04-09 11:04:32 +02:00
my @vertical_lines = ();
2012-09-12 15:22:43 +02:00
for ( my $i = 0 ; $x <= $bounding_box -> [ X2 ] + scaled_epsilon ; $i ++ ) {
2012-02-25 22:15:34 +01:00
my $vertical_line = Slic3r::Line -> new ([ $x , $bounding_box -> [ Y2 ]], [ $x , $bounding_box -> [ Y1 ]]);
2011-11-14 10:31:07 +01:00
if ( $is_line_pattern && $i % 2 ) {
2012-03-04 11:45:45 +01:00
$vertical_line -> [ A ][ X ] += $line_oscillation ;
$vertical_line -> [ B ][ X ] -= $line_oscillation ;
2011-11-14 10:31:07 +01:00
}
2012-04-09 11:04:32 +02:00
push @vertical_lines , $vertical_line ;
2011-12-04 16:24:46 +01:00
$x += $distance_between_lines ;
}
2012-08-24 18:59:23 +02: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 11:04:32 +02:00
my @paths = @ { Boost::Geometry::Utils:: polygon_linestring_intersection (
2012-09-12 15:22:43 +02: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 11:04:32 +02:00
Boost::Geometry::Utils:: linestring ( @vertical_lines ),
) };
for ( @paths ) {
$_ -> [ 0 ][ Y ] += $overlap_distance ;
$_ -> [ - 1 ][ Y ] -= $overlap_distance ;
}
2011-12-04 16:24:46 +01:00
# connect lines
2012-10-24 16:17:09 +02:00
unless ( $params { dont_connect }) {
2012-10-30 14:07:01 +01:00
my $collection = Slic3r::Polyline::Collection -> new (
polylines => [ map Slic3r::Polyline -> new ( @$_ ), @paths ],
2011-12-04 16:24:46 +01:00
);
@paths = ();
2012-09-12 15:22:43 +02:00
my $tolerance = 10 * scaled_epsilon ;
2012-05-04 20:51:09 +02: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 20:27:28 +02:00
&& $_ [ Y ] <= $diagonal_distance
2012-05-04 20:51:09 +02:00
}
2012-06-23 22:43:23 +02:00
: sub { abs ( $_ [ X ] - $distance_between_lines ) <= $tolerance && $_ [ Y ] <= $diagonal_distance };
2011-12-04 16:24:46 +01:00
foreach my $path ( $collection -> shortest_path ) {
if ( @paths ) {
2012-10-30 14:07:01 +01:00
my @distance = map abs ( $path -> [ 0 ][ $_ ] - $paths [ - 1 ][ - 1 ][ $_ ]), ( X , Y );
2011-12-04 16:24:46 +01: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 14:07:01 +01: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 16:24:46 +01:00
next ;
}
}
2012-10-30 14:07:01 +01:00
push @paths , $path ;
2011-12-04 16:24:46 +01:00
}
2011-10-06 13:43:32 +02:00
}
# paths must be rotated back
$self -> rotate_points_back ( \ @paths , $rotate_vector );
2011-12-17 19:52:34 +01:00
return { flow_spacing => $flow_spacing }, @paths ;
2011-09-05 12:21:27 +02:00
}
1 ;