2018-02-22 08:56:05 +00:00
# include "../ClipperUtils.hpp"
# include "../PolylineCollection.hpp"
# include "../Surface.hpp"
# include <cmath>
# include <algorithm>
# include <iostream>
# include "FillGyroid.hpp"
namespace Slic3r {
2018-04-13 14:43:35 +00:00
static inline double f ( double x , double z_sin , double z_cos , bool vertical , bool flip )
2018-02-23 17:32:35 +00:00
{
2018-04-13 11:46:31 +00:00
if ( vertical ) {
double phase_offset = ( z_cos < 0 ? M_PI : 0 ) + M_PI ;
double a = sin ( x + phase_offset ) ;
2018-02-23 17:32:35 +00:00
double b = - z_cos ;
2018-04-13 11:46:31 +00:00
double res = z_sin * cos ( x + phase_offset + ( flip ? M_PI : 0. ) ) ;
2018-02-23 17:32:35 +00:00
double r = sqrt ( sqr ( a ) + sqr ( b ) ) ;
2018-04-13 11:46:31 +00:00
return asin ( a / r ) + asin ( res / r ) + M_PI ;
}
else {
double phase_offset = z_sin < 0 ? M_PI : 0. ;
double a = cos ( x + phase_offset ) ;
double b = - z_sin ;
double res = z_cos * sin ( x + phase_offset + ( flip ? 0 : M_PI ) ) ;
double r = sqrt ( sqr ( a ) + sqr ( b ) ) ;
return ( asin ( a / r ) + asin ( res / r ) + 0.5 * M_PI ) ;
2018-02-22 08:56:05 +00:00
}
}
2018-04-13 11:46:31 +00:00
static inline Polyline make_wave (
2018-08-21 19:05:24 +00:00
const std : : vector < Vec2d > & one_period , double width , double height , double offset , double scaleFactor ,
2018-04-13 11:46:31 +00:00
double z_cos , double z_sin , bool vertical )
2018-02-23 17:32:35 +00:00
{
2018-08-21 19:05:24 +00:00
std : : vector < Vec2d > points = one_period ;
2018-08-17 13:53:43 +00:00
double period = points . back ( ) ( 0 ) ;
2019-06-22 13:59:54 +00:00
points . reserve ( one_period . size ( ) * floor ( width / period ) ) ;
2018-04-13 11:46:31 +00:00
points . pop_back ( ) ;
int n = points . size ( ) ;
do {
2018-08-21 19:05:24 +00:00
points . emplace_back ( Vec2d ( points [ points . size ( ) - n ] ( 0 ) + period , points [ points . size ( ) - n ] ( 1 ) ) ) ;
2018-08-17 13:53:43 +00:00
} while ( points . back ( ) ( 0 ) < width ) ;
points . back ( ) ( 0 ) = width ;
2018-04-13 11:46:31 +00:00
// and construct the final polyline to return:
2018-02-22 08:56:05 +00:00
Polyline polyline ;
2019-06-22 13:59:54 +00:00
polyline . points . reserve ( points . size ( ) ) ;
2018-04-13 11:46:31 +00:00
for ( auto & point : points ) {
2018-08-17 13:53:43 +00:00
point ( 1 ) + = offset ;
point ( 1 ) = clamp ( 0. , height , double ( point ( 1 ) ) ) ;
2018-04-13 11:46:31 +00:00
if ( vertical )
2018-08-17 13:53:43 +00:00
std : : swap ( point ( 0 ) , point ( 1 ) ) ;
Removed Point::scale(),translate(),coincides_with(),distance_to(),
distance_to_squared(),perp_distance_to(),negative(),vector_to(),
translate(), distance_to() etc,
replaced with the Eigen equivalents.
2018-08-17 12:14:24 +00:00
polyline . points . emplace_back ( ( point * scaleFactor ) . cast < coord_t > ( ) ) ;
2018-02-22 08:56:05 +00:00
}
2018-04-13 11:46:31 +00:00
2018-02-22 08:56:05 +00:00
return polyline ;
}
2019-06-19 22:27:22 +00:00
static std : : vector < Vec2d > make_one_period ( double width , double scaleFactor , double z_cos , double z_sin , bool vertical , bool flip , double tolerance )
2018-04-13 14:43:35 +00:00
{
2018-08-21 19:05:24 +00:00
std : : vector < Vec2d > points ;
2019-06-19 22:27:22 +00:00
double dx = M_PI_2 ; // exact coordinates on main inflexion lobes
2018-04-13 11:46:31 +00:00
double limit = std : : min ( 2 * M_PI , width ) ;
2019-06-22 13:59:54 +00:00
points . reserve ( ceil ( limit / tolerance / 3 ) ) ;
2018-04-13 11:46:31 +00:00
for ( double x = 0. ; x < limit + EPSILON ; x + = dx ) { // so the last point is there too
x = std : : min ( x , limit ) ;
2019-06-19 22:27:22 +00:00
points . emplace_back ( Vec2d ( x , f ( x , z_sin , z_cos , vertical , flip ) ) ) ;
2018-04-13 11:46:31 +00:00
}
2019-06-19 22:27:22 +00:00
// piecewise increase in resolution up to requested tolerance
for ( ; ; )
{
size_t size = points . size ( ) ;
for ( unsigned int i = 1 ; i < size ; + + i ) {
auto & lp = points [ i - 1 ] ; // left point
auto & rp = points [ i ] ; // right point
double x = lp ( 0 ) + ( rp ( 0 ) - lp ( 0 ) ) / 2 ;
double y = f ( x , z_sin , z_cos , vertical , flip ) ;
Vec2d ip = { x , y } ;
if ( std : : abs ( cross2 ( Vec2d ( ip - lp ) , Vec2d ( ip - rp ) ) ) > sqr ( tolerance ) ) {
points . emplace_back ( std : : move ( ip ) ) ;
}
}
if ( size = = points . size ( ) )
break ;
else
{
// insert new points in order
std : : sort ( points . begin ( ) , points . end ( ) ,
[ ] ( const Vec2d & lhs , const Vec2d & rhs ) { return lhs ( 0 ) < rhs ( 0 ) ; } ) ;
2018-04-13 11:46:31 +00:00
}
}
2019-06-19 22:27:22 +00:00
2018-04-13 11:46:31 +00:00
return points ;
}
2018-04-05 08:31:53 +00:00
static Polylines make_gyroid_waves ( double gridZ , double density_adjusted , double line_spacing , double width , double height )
2018-02-22 08:56:05 +00:00
{
2018-04-13 11:46:31 +00:00
const double scaleFactor = scale_ ( line_spacing ) / density_adjusted ;
2019-06-19 22:27:22 +00:00
// tolerance (in scaled units)
// TODO: should consider layer thickness
const double tolerance = line_spacing / 2 / unscale < double > ( scaleFactor ) ;
2018-02-23 17:32:35 +00:00
//scale factor for 5% : 8 712 388
// 1z = 10^-6 mm ?
2018-04-13 11:46:31 +00:00
const double z = gridZ / scaleFactor ;
const double z_sin = sin ( z ) ;
const double z_cos = cos ( z ) ;
bool vertical = ( std : : abs ( z_sin ) < = std : : abs ( z_cos ) ) ;
double lower_bound = 0. ;
double upper_bound = height ;
bool flip = true ;
if ( vertical ) {
flip = false ;
lower_bound = - M_PI ;
upper_bound = width - M_PI_2 ;
std : : swap ( width , height ) ;
2018-02-22 08:56:05 +00:00
}
2018-04-13 11:46:31 +00:00
2019-06-19 22:27:22 +00:00
std : : vector < Vec2d > one_period_odd = make_one_period ( width , scaleFactor , z_cos , z_sin , vertical , flip , tolerance ) ; // creates one period of the waves, so it doesn't have to be recalculated all the time
2019-01-23 09:08:42 +00:00
flip = ! flip ; // even polylines are a bit shifted
2019-06-19 22:27:22 +00:00
std : : vector < Vec2d > one_period_even = make_one_period ( width , scaleFactor , z_cos , z_sin , vertical , flip , tolerance ) ;
2018-04-13 11:46:31 +00:00
Polylines result ;
2019-01-23 09:08:42 +00:00
for ( double y0 = lower_bound ; y0 < upper_bound + EPSILON ; y0 + = M_PI ) {
// creates odd polylines
result . emplace_back ( make_wave ( one_period_odd , width , height , y0 , scaleFactor , z_cos , z_sin , vertical ) ) ;
// creates even polylines
y0 + = M_PI ;
if ( y0 < upper_bound + EPSILON ) {
result . emplace_back ( make_wave ( one_period_even , width , height , y0 , scaleFactor , z_cos , z_sin , vertical ) ) ;
}
}
2018-04-13 11:46:31 +00:00
2018-02-22 08:56:05 +00:00
return result ;
}
void FillGyroid : : _fill_surface_single (
const FillParams & params ,
unsigned int thickness_layers ,
const std : : pair < float , Point > & direction ,
ExPolygon & expolygon ,
Polylines & polylines_out )
{
2018-04-05 08:31:53 +00:00
// no rotation is supported for this infill pattern (yet)
2018-02-22 08:56:05 +00:00
BoundingBox bb = expolygon . contour . bounding_box ( ) ;
2018-04-05 08:31:53 +00:00
// Density adjusted to have a good %of weight.
2018-12-11 15:33:43 +00:00
double density_adjusted = std : : max ( 0. , params . density * 2.44 ) ;
2018-04-05 08:31:53 +00:00
// Distance between the gyroid waves in scaled coordinates.
coord_t distance = coord_t ( scale_ ( this - > spacing ) / density_adjusted ) ;
2018-02-22 08:56:05 +00:00
// align bounding box to a multiple of our grid module
2018-04-05 08:31:53 +00:00
bb . merge ( _align_to_grid ( bb . min , Point ( 2. * M_PI * distance , 2. * M_PI * distance ) ) ) ;
2018-04-13 11:46:31 +00:00
2018-02-22 08:56:05 +00:00
// generate pattern
2019-01-23 09:08:42 +00:00
Polylines polylines_square = make_gyroid_waves (
2018-02-23 17:32:35 +00:00
scale_ ( this - > z ) ,
2018-04-05 08:31:53 +00:00
density_adjusted ,
2018-02-22 08:56:05 +00:00
this - > spacing ,
2018-08-17 13:53:43 +00:00
ceil ( bb . size ( ) ( 0 ) / distance ) + 1. ,
ceil ( bb . size ( ) ( 1 ) / distance ) + 1. ) ;
2018-02-22 08:56:05 +00:00
// move pattern in place
2019-01-23 09:08:42 +00:00
for ( Polyline & polyline : polylines_square )
2018-08-17 13:53:43 +00:00
polyline . translate ( bb . min ( 0 ) , bb . min ( 1 ) ) ;
2018-02-22 08:56:05 +00:00
2019-01-23 09:08:42 +00:00
// clip pattern to boundaries, keeping the polyline order & ordering the fragment to be able to join them easily
//Polylines polylines = intersection_pl(polylines_square, (Polygons)expolygon);
Polylines polylines_chained ;
for ( size_t idx_polyline = 0 ; idx_polyline < polylines_square . size ( ) ; + + idx_polyline ) {
Polyline & poly_to_cut = polylines_square [ idx_polyline ] ;
Polylines polylines_to_sort = intersection_pl ( Polylines ( ) = { poly_to_cut } , ( Polygons ) expolygon ) ;
for ( Polyline & polyline : polylines_to_sort ) {
//TODO: replace by closest_index_point()
if ( idx_polyline % 2 = = 0 ) {
if ( poly_to_cut . points . front ( ) . distance_to_square ( polyline . points . front ( ) ) > poly_to_cut . points . front ( ) . distance_to_square ( polyline . points . back ( ) ) ) {
polyline . reverse ( ) ;
}
} else {
if ( poly_to_cut . points . back ( ) . distance_to_square ( polyline . points . front ( ) ) > poly_to_cut . points . back ( ) . distance_to_square ( polyline . points . back ( ) ) ) {
polyline . reverse ( ) ;
}
2018-02-22 08:56:05 +00:00
}
}
2019-01-23 09:08:42 +00:00
if ( polylines_to_sort . size ( ) > 1 ) {
Point nearest = poly_to_cut . points . front ( ) ;
if ( idx_polyline % 2 ! = 0 ) {
nearest = poly_to_cut . points . back ( ) ;
}
//Bubble sort
for ( size_t idx_sort = polylines_to_sort . size ( ) - 1 ; idx_sort > 0 ; idx_sort - - ) {
for ( size_t idx_bubble = 0 ; idx_bubble < idx_sort ; idx_bubble + + ) {
if ( polylines_to_sort [ idx_bubble + 1 ] . points . front ( ) . distance_to_square ( nearest ) < polylines_to_sort [ idx_bubble ] . points . front ( ) . distance_to_square ( nearest ) ) {
iter_swap ( polylines_to_sort . begin ( ) + idx_bubble , polylines_to_sort . begin ( ) + idx_bubble + 1 ) ;
}
2018-02-22 08:56:05 +00:00
}
}
2019-01-23 09:08:42 +00:00
}
polylines_chained . insert ( polylines_chained . end ( ) , polylines_to_sort . begin ( ) , polylines_to_sort . end ( ) ) ;
}
2019-03-08 17:29:51 +00:00
size_t polylines_out_first_idx = polylines_out . size ( ) ;
2019-01-23 09:08:42 +00:00
if ( ! polylines_chained . empty ( ) ) {
// connect lines
if ( params . dont_connect ) {
polylines_out . insert ( polylines_out . end ( ) , polylines_chained . begin ( ) , polylines_chained . end ( ) ) ;
} else {
2019-03-08 17:29:51 +00:00
this - > connect_infill ( polylines_chained , expolygon , polylines_out , params ) ;
}
}
//remove too small bits (larger than longer);
for ( size_t idx = polylines_out_first_idx ; idx < polylines_out . size ( ) ; idx + + ) {
if ( polylines_out [ idx ] . length ( ) < scale_ ( this - > spacing * 3 ) ) {
polylines_out . erase ( polylines_out . begin ( ) + idx ) ;
idx - - ;
2018-02-22 08:56:05 +00:00
}
}
}
} // namespace Slic3r