2016-04-11 17:08:30 +02:00
#include "../ClipperUtils.hpp"
#include "../ExPolygon.hpp"
2019-09-27 09:51:07 +02:00
#include "../ShortestPath.hpp"
2016-04-11 17:08:30 +02:00
#include "../Surface.hpp"
#include "FillRectilinear.hpp"
namespace Slic3r {
2020-11-16 11:16:44 +01:00
void FillLine :: _fill_surface_single (
2016-09-13 11:26:38 +02:00
const FillParams & params ,
unsigned int thickness_layers ,
const std :: pair < float , Point > & direction ,
ExPolygon & expolygon ,
Polylines & polylines_out )
2016-04-11 17:08:30 +02:00
{
// rotate polygons so that we can work with vertical lines here
2016-09-13 11:26:38 +02:00
expolygon . rotate ( - direction . first );
2016-04-11 17:08:30 +02:00
this -> _min_spacing = scale_ ( this -> spacing );
assert ( params . density > 0.0001f && params . density <= 1.f );
this -> _line_spacing = coord_t ( coordf_t ( this -> _min_spacing ) / params . density );
this -> _diagonal_distance = this -> _line_spacing * 2 ;
this -> _line_oscillation = this -> _line_spacing - this -> _min_spacing ; // only for Line infill
BoundingBox bounding_box = expolygon . contour . bounding_box ();
// define flow spacing according to requested density
if ( params . density > 0.9999f && ! params . dont_adjust ) {
2018-08-17 15:53:43 +02:00
this -> _line_spacing = this -> _adjust_solid_spacing ( bounding_box . size ()( 0 ), this -> _line_spacing );
2018-08-21 17:43:05 +02:00
this -> spacing = unscale < double > ( this -> _line_spacing );
2016-04-11 17:08:30 +02:00
} else {
// extend bounding box so that our pattern will be aligned with other layers
2016-09-13 11:26:38 +02:00
// Transform the reference point to the rotated coordinate system.
bounding_box . merge ( _align_to_grid (
bounding_box . min ,
Point ( this -> _line_spacing , this -> _line_spacing ),
direction . second . rotated ( - direction . first )));
2016-04-11 17:08:30 +02:00
}
2016-04-13 20:45:44 +02:00
2016-04-11 17:08:30 +02:00
// generate the basic pattern
2018-08-17 15:53:43 +02:00
coord_t x_max = bounding_box . max ( 0 ) + SCALED_EPSILON ;
2016-04-11 17:08:30 +02:00
Lines lines ;
2018-08-17 15:53:43 +02:00
for ( coord_t x = bounding_box . min ( 0 ); x <= x_max ; x += this -> _line_spacing )
lines . push_back ( this -> _line ( lines . size (), x , bounding_box . min ( 1 ), bounding_box . max ( 1 )));
2016-04-11 17:08:30 +02:00
// clip paths against a slightly larger expolygon, so that the first and last paths
// are kept even if the expolygon has vertical sides
// the minimum offset for preventing edge lines from being clipped is SCALED_EPSILON;
// however we use a larger offset to support expolygons with slightly skewed sides and
// not perfectly straight
//FIXME Vojtech: Update the intersecton function to work directly with lines.
Polylines polylines_src ;
polylines_src . reserve ( lines . size ());
for ( Lines :: const_iterator it = lines . begin (); it != lines . end (); ++ it ) {
polylines_src . push_back ( Polyline ());
Points & pts = polylines_src . back (). points ;
pts . reserve ( 2 );
pts . push_back ( it -> a );
pts . push_back ( it -> b );
}
2016-12-13 19:22:23 +01:00
Polylines polylines = intersection_pl ( polylines_src , offset ( to_polygons ( expolygon ), scale_ ( 0.02 )), false );
2016-04-11 17:08:30 +02:00
// FIXME Vojtech: This is only performed for horizontal lines, not for the vertical lines!
const float INFILL_OVERLAP_OVER_SPACING = 0.3f ;
2016-09-13 11:26:38 +02:00
// How much to extend an infill path from expolygon outside?
2016-04-11 17:08:30 +02:00
coord_t extra = coord_t ( floor ( this -> _min_spacing * INFILL_OVERLAP_OVER_SPACING + 0.5f ));
for ( Polylines :: iterator it_polyline = polylines . begin (); it_polyline != polylines . end (); ++ it_polyline ) {
Point * first_point = & it_polyline -> points . front ();
Point * last_point = & it_polyline -> points . back ();
2018-08-14 18:33:26 +02:00
if ( first_point -> y () > last_point -> y ())
2016-04-11 17:08:30 +02:00
std :: swap ( first_point , last_point );
2018-08-14 18:33:26 +02:00
first_point -> y () -= extra ;
last_point -> y () += extra ;
2016-04-11 17:08:30 +02:00
}
2016-09-13 11:26:38 +02:00
size_t n_polylines_out_old = polylines_out . size ();
2016-04-11 17:08:30 +02:00
// connect lines
if ( ! params . dont_connect && ! polylines . empty ()) { // prevent calling leftmost_point() on empty collections
// offset the expolygon by max(min_spacing/2, extra)
ExPolygon expolygon_off ;
{
ExPolygons expolygons_off = offset_ex ( expolygon , this -> _min_spacing / 2 );
if ( ! expolygons_off . empty ()) {
// When expanding a polygon, the number of islands could only shrink. Therefore the offset_ex shall generate exactly one expanded island for one input island.
assert ( expolygons_off . size () == 1 );
std :: swap ( expolygon_off , expolygons_off . front ());
}
}
2016-09-13 11:26:38 +02:00
bool first = true ;
2019-09-27 18:17:21 +02:00
for ( Polyline & polyline : chain_polylines ( std :: move ( polylines ))) {
2016-09-13 11:26:38 +02:00
if ( ! first ) {
2016-04-11 17:08:30 +02:00
// Try to connect the lines.
2016-09-13 11:26:38 +02:00
Points & pts_end = polylines_out . back (). points ;
2019-09-27 09:51:07 +02:00
const Point & first_point = polyline . points . front ();
2016-04-11 17:08:30 +02:00
const Point & last_point = pts_end . back ();
// Distance in X, Y.
2018-08-17 14:14:24 +02:00
const Vector distance = last_point - first_point ;
2016-04-11 17:08:30 +02:00
// TODO: we should also check that both points are on a fill_boundary to avoid
// connecting paths on the boundaries of internal regions
2018-08-17 15:53:43 +02:00
if ( this -> _can_connect ( std :: abs ( distance ( 0 )), std :: abs ( distance ( 1 ))) &&
2016-04-11 17:08:30 +02:00
expolygon_off . contains ( Line ( last_point , first_point ))) {
// Append the polyline.
2019-09-27 09:51:07 +02:00
pts_end . insert ( pts_end . end (), polyline . points . begin (), polyline . points . end ());
2016-04-11 17:08:30 +02:00
continue ;
}
}
// The lines cannot be connected.
2019-09-27 09:51:07 +02:00
polylines_out . emplace_back ( std :: move ( polyline ));
2016-09-13 11:26:38 +02:00
first = false ;
2016-04-11 17:08:30 +02:00
}
}
// paths must be rotated back
2016-09-13 11:26:38 +02:00
for ( Polylines :: iterator it = polylines_out . begin () + n_polylines_out_old ; it != polylines_out . end (); ++ it ) {
2016-04-11 17:08:30 +02:00
// No need to translate, the absolute position is irrelevant.
2018-08-17 15:53:43 +02:00
// it->translate(- direction.second(0), - direction.second(1));
2016-09-13 11:26:38 +02:00
it -> rotate ( direction . first );
2016-04-11 17:08:30 +02:00
}
}
} // namespace Slic3r