2019-11-11 10:41:14 +00:00
# ifndef SLA_SUPPORTPOINTGENERATOR_HPP
# define SLA_SUPPORTPOINTGENERATOR_HPP
2020-01-15 16:44:15 +00:00
# include <random>
2019-11-11 10:41:14 +00:00
# include <libslic3r/SLA/SupportPoint.hpp>
2020-06-25 11:58:51 +00:00
# include <libslic3r/SLA/IndexedMesh.hpp>
2018-12-07 13:10:16 +00:00
2020-05-22 15:21:54 +00:00
# include <libslic3r/BoundingBox.hpp>
2019-02-20 10:16:31 +00:00
# include <libslic3r/ClipperUtils.hpp>
2018-12-07 13:10:16 +00:00
# include <libslic3r/Point.hpp>
2018-12-07 13:10:16 +00:00
2019-02-18 10:46:06 +00:00
# include <boost/container/small_vector.hpp>
2019-11-11 10:41:14 +00:00
// #define SLA_SUPPORTPOINTGEN_DEBUG
2018-12-07 13:10:16 +00:00
2019-11-11 10:41:14 +00:00
namespace Slic3r { namespace sla {
2018-12-07 13:10:16 +00:00
2019-11-11 10:41:14 +00:00
class SupportPointGenerator {
2018-12-07 13:10:16 +00:00
public :
struct Config {
2019-11-11 10:41:14 +00:00
float density_relative { 1.f } ;
float minimal_distance { 1.f } ;
float head_diameter { 0.4f } ;
2020-09-10 11:37:58 +00:00
// Originally calibrated to 7.7f, reduced density by Tamas to 70% which is 11.1 (7.7 / 0.7) to adjust for new algorithm changes in tm_suppt_gen_improve
inline float support_force ( ) const { return 11.1f / density_relative ; } // a force one point can support (arbitrary force unit)
2019-11-11 10:41:14 +00:00
inline float tear_pressure ( ) const { return 1.f ; } // pressure that the display exerts (the force unit per mm2)
} ;
2020-06-25 11:58:51 +00:00
SupportPointGenerator ( const IndexedMesh & emesh , const std : : vector < ExPolygons > & slices ,
2019-11-11 10:41:14 +00:00
const std : : vector < float > & heights , const Config & config , std : : function < void ( void ) > throw_on_cancel , std : : function < void ( int ) > statusfn ) ;
2020-06-25 11:58:51 +00:00
SupportPointGenerator ( const IndexedMesh & emesh , const Config & config , std : : function < void ( void ) > throw_on_cancel , std : : function < void ( int ) > statusfn ) ;
2020-01-13 12:57:39 +00:00
2020-01-14 09:41:42 +00:00
const std : : vector < SupportPoint > & output ( ) const { return m_output ; }
std : : vector < SupportPoint > & output ( ) { return m_output ; }
2019-11-11 10:41:14 +00:00
struct MyLayer ;
2019-09-24 13:15:49 +00:00
2019-01-30 07:26:23 +00:00
struct Structure {
2020-08-31 08:38:24 +00:00
Structure ( MyLayer & layer , const ExPolygon & poly , const BoundingBox & bbox , const Vec2f & centroid , float area , float h ) :
layer ( & layer ) , polygon ( & poly ) , bbox ( bbox ) , centroid ( centroid ) , area ( area ) , zlevel ( h )
2019-11-11 10:41:14 +00:00
# ifdef SLA_SUPPORTPOINTGEN_DEBUG
2019-02-06 09:57:45 +00:00
, unique_id ( std : : chrono : : duration_cast < std : : chrono : : milliseconds > ( std : : chrono : : system_clock : : now ( ) . time_since_epoch ( ) ) )
2019-11-11 10:41:14 +00:00
# endif /* SLA_SUPPORTPOINTGEN_DEBUG */
{ }
2019-02-18 10:46:06 +00:00
MyLayer * layer ;
2019-01-30 07:26:23 +00:00
const ExPolygon * polygon = nullptr ;
2019-02-06 09:57:45 +00:00
const BoundingBox bbox ;
2019-02-06 10:09:00 +00:00
const Vec2f centroid = Vec2f : : Zero ( ) ;
2019-02-06 09:57:45 +00:00
const float area = 0.f ;
2020-08-31 08:38:24 +00:00
float zlevel = 0 ;
2019-02-06 09:57:45 +00:00
// How well is this ExPolygon held to the print base?
// Positive number, the higher the better.
2019-02-19 09:09:41 +00:00
float supports_force_this_layer = 0.f ;
float supports_force_inherited = 0.f ;
float supports_force_total ( ) const { return this - > supports_force_this_layer + this - > supports_force_inherited ; }
2019-11-11 10:41:14 +00:00
# ifdef SLA_SUPPORTPOINTGEN_DEBUG
2019-01-30 07:26:23 +00:00
std : : chrono : : milliseconds unique_id ;
2019-11-11 10:41:14 +00:00
# endif /* SLA_SUPPORTPOINTGEN_DEBUG */
2019-02-20 09:46:49 +00:00
struct Link {
2019-11-11 10:41:14 +00:00
Link ( Structure * island , float overlap_area ) : island ( island ) , overlap_area ( overlap_area ) { }
2019-02-20 09:46:49 +00:00
Structure * island ;
float overlap_area ;
} ;
2019-02-19 09:09:41 +00:00
# ifdef NDEBUG
2019-11-11 10:41:14 +00:00
// In release mode, use the optimized container.
2019-02-20 09:46:49 +00:00
boost : : container : : small_vector < Link , 4 > islands_above ;
boost : : container : : small_vector < Link , 4 > islands_below ;
2019-02-19 09:09:41 +00:00
# else
2019-11-11 10:41:14 +00:00
// In debug mode, use the standard vector, which is well handled by debugger visualizer.
std : : vector < Link > islands_above ;
std : : vector < Link > islands_below ;
2019-02-19 09:09:41 +00:00
# endif
2019-02-27 07:49:09 +00:00
// Overhangs, that are dangling considerably.
2019-02-20 09:46:49 +00:00
ExPolygons dangling_areas ;
2019-02-27 07:49:09 +00:00
// Complete overhands.
2019-02-20 09:46:49 +00:00
ExPolygons overhangs ;
2019-02-27 07:49:09 +00:00
// Overhangs, where the surface must slope.
ExPolygons overhangs_slopes ;
2020-01-14 09:24:15 +00:00
float overhangs_area = 0.f ;
2019-11-11 10:41:14 +00:00
2019-02-20 09:46:49 +00:00
bool overlaps ( const Structure & rhs ) const {
return this - > bbox . overlap ( rhs . bbox ) & & ( this - > polygon - > overlaps ( * rhs . polygon ) | | rhs . polygon - > overlaps ( * this - > polygon ) ) ;
}
float overlap_area ( const Structure & rhs ) const {
double out = 0. ;
if ( this - > bbox . overlap ( rhs . bbox ) ) {
2019-11-11 10:41:14 +00:00
Polygons polys = intersection ( to_polygons ( * this - > polygon ) , to_polygons ( * rhs . polygon ) , false ) ;
for ( const Polygon & poly : polys )
2019-02-20 09:46:49 +00:00
out + = poly . area ( ) ;
}
return float ( out ) ;
}
2019-02-06 09:57:45 +00:00
float area_below ( ) const {
float area = 0.f ;
2019-02-20 09:46:49 +00:00
for ( const Link & below : this - > islands_below )
area + = below . island - > area ;
2019-02-06 09:57:45 +00:00
return area ;
}
Polygons polygons_below ( ) const {
size_t cnt = 0 ;
2019-11-11 10:41:14 +00:00
for ( const Link & below : this - > islands_below )
2019-02-20 09:46:49 +00:00
cnt + = 1 + below . island - > polygon - > holes . size ( ) ;
2019-02-06 09:57:45 +00:00
Polygons out ;
out . reserve ( cnt ) ;
2019-11-11 10:41:14 +00:00
for ( const Link & below : this - > islands_below ) {
2019-02-20 09:46:49 +00:00
out . emplace_back ( below . island - > polygon - > contour ) ;
2019-11-11 10:41:14 +00:00
append ( out , below . island - > polygon - > holes ) ;
2019-02-06 09:57:45 +00:00
}
return out ;
}
ExPolygons expolygons_below ( ) const {
ExPolygons out ;
2019-02-18 10:46:06 +00:00
out . reserve ( this - > islands_below . size ( ) ) ;
2019-02-20 09:46:49 +00:00
for ( const Link & below : this - > islands_below )
out . emplace_back ( * below . island - > polygon ) ;
2019-02-06 09:57:45 +00:00
return out ;
}
2019-02-19 09:09:41 +00:00
// Positive deficit of the supports. If negative, this area is well supported. If positive, more supports need to be added.
float support_force_deficit ( const float tear_pressure ) const { return this - > area * tear_pressure - this - > supports_force_total ( ) ; }
2019-01-30 07:26:23 +00:00
} ;
2019-11-11 10:41:14 +00:00
2019-02-18 10:46:06 +00:00
struct MyLayer {
2019-11-11 10:41:14 +00:00
MyLayer ( const size_t layer_id , coordf_t print_z ) : layer_id ( layer_id ) , print_z ( print_z ) { }
2019-02-18 10:46:06 +00:00
size_t layer_id ;
coordf_t print_z ;
std : : vector < Structure > islands ;
} ;
2019-11-11 10:41:14 +00:00
2019-02-18 10:46:06 +00:00
struct RichSupportPoint {
Vec3f position ;
Structure * island ;
} ;
2019-11-11 10:41:14 +00:00
2019-02-18 10:46:06 +00:00
struct PointGrid3D {
struct GridHash {
2019-02-18 11:47:15 +00:00
std : : size_t operator ( ) ( const Vec3i & cell_id ) const {
2019-02-18 10:46:06 +00:00
return std : : hash < int > ( ) ( cell_id . x ( ) ) ^ std : : hash < int > ( ) ( cell_id . y ( ) * 593 ) ^ std : : hash < int > ( ) ( cell_id . z ( ) * 7919 ) ;
}
} ;
typedef std : : unordered_multimap < Vec3i , RichSupportPoint , GridHash > Grid ;
2019-11-11 10:41:14 +00:00
2019-02-18 10:46:06 +00:00
Vec3f cell_size ;
Grid grid ;
2019-11-11 10:41:14 +00:00
2019-02-18 10:46:06 +00:00
Vec3i cell_id ( const Vec3f & pos ) {
return Vec3i ( int ( floor ( pos . x ( ) / cell_size . x ( ) ) ) ,
int ( floor ( pos . y ( ) / cell_size . y ( ) ) ) ,
int ( floor ( pos . z ( ) / cell_size . z ( ) ) ) ) ;
}
2019-11-11 10:41:14 +00:00
2019-02-18 10:46:06 +00:00
void insert ( const Vec2f & pos , Structure * island ) {
RichSupportPoint pt ;
2019-11-11 10:41:14 +00:00
pt . position = Vec3f ( pos . x ( ) , pos . y ( ) , float ( island - > layer - > print_z ) ) ;
2019-02-18 10:46:06 +00:00
pt . island = island ;
grid . emplace ( cell_id ( pt . position ) , pt ) ;
}
2019-11-11 10:41:14 +00:00
2020-08-31 08:38:24 +00:00
bool collides_with ( const Vec2f & pos , float print_z , float radius ) {
Vec3f pos3d ( pos . x ( ) , pos . y ( ) , print_z ) ;
2019-02-18 10:46:06 +00:00
Vec3i cell = cell_id ( pos3d ) ;
std : : pair < Grid : : const_iterator , Grid : : const_iterator > it_pair = grid . equal_range ( cell ) ;
if ( collides_with ( pos3d , radius , it_pair . first , it_pair . second ) )
return true ;
for ( int i = - 1 ; i < 2 ; + + i )
for ( int j = - 1 ; j < 2 ; + + j )
for ( int k = - 1 ; k < 1 ; + + k ) {
if ( i = = 0 & & j = = 0 & & k = = 0 )
continue ;
it_pair = grid . equal_range ( cell + Vec3i ( i , j , k ) ) ;
if ( collides_with ( pos3d , radius , it_pair . first , it_pair . second ) )
return true ;
}
return false ;
}
2019-11-11 10:41:14 +00:00
2019-02-18 10:46:06 +00:00
private :
bool collides_with ( const Vec3f & pos , float radius , Grid : : const_iterator it_begin , Grid : : const_iterator it_end ) {
for ( Grid : : const_iterator it = it_begin ; it ! = it_end ; + + it ) {
2019-11-11 10:41:14 +00:00
float dist2 = ( it - > second . position - pos ) . squaredNorm ( ) ;
2019-02-18 10:46:06 +00:00
if ( dist2 < radius * radius )
return true ;
}
return false ;
}
} ;
2019-11-11 10:41:14 +00:00
2020-01-13 12:57:39 +00:00
void execute ( const std : : vector < ExPolygons > & slices ,
const std : : vector < float > & heights ) ;
2020-01-15 16:44:15 +00:00
void seed ( std : : mt19937 : : result_type s ) { m_rng . seed ( s ) ; }
2019-02-18 10:46:06 +00:00
private :
2019-11-11 10:41:14 +00:00
std : : vector < SupportPoint > m_output ;
SupportPointGenerator : : Config m_config ;
2020-01-15 16:44:15 +00:00
void process ( const std : : vector < ExPolygons > & slices , const std : : vector < float > & heights ) ;
2020-08-31 08:38:24 +00:00
public :
enum IslandCoverageFlags : uint8_t { icfNone = 0x0 , icfIsNew = 0x1 , icfBoundaryOnly = 0x2 } ;
private :
void uniformly_cover ( const ExPolygons & islands , Structure & structure , float deficit , PointGrid3D & grid3d , IslandCoverageFlags flags = icfNone ) ;
void add_support_points ( Structure & structure , PointGrid3D & grid3d ) ;
2019-11-11 10:41:14 +00:00
void project_onto_mesh ( std : : vector < SupportPoint > & points ) const ;
2019-01-30 07:26:23 +00:00
2019-11-11 10:41:14 +00:00
# ifdef SLA_SUPPORTPOINTGEN_DEBUG
2019-02-06 09:57:45 +00:00
static void output_expolygons ( const ExPolygons & expolys , const std : : string & filename ) ;
static void output_structures ( const std : : vector < Structure > & structures ) ;
2019-11-11 10:41:14 +00:00
# endif // SLA_SUPPORTPOINTGEN_DEBUG
2020-06-25 11:58:51 +00:00
const IndexedMesh & m_emesh ;
2019-04-02 08:54:14 +00:00
std : : function < void ( void ) > m_throw_on_cancel ;
std : : function < void ( int ) > m_statusfn ;
2020-01-15 16:44:15 +00:00
std : : mt19937 m_rng ;
2018-12-07 13:10:16 +00:00
} ;
2020-06-02 15:28:46 +00:00
void remove_bottom_points ( std : : vector < SupportPoint > & pts , float lvl ) ;
2018-12-07 13:10:16 +00:00
2020-08-31 08:38:24 +00:00
std : : vector < Vec2f > sample_expolygon ( const ExPolygon & expoly , float samples_per_mm2 , std : : mt19937 & rng ) ;
void sample_expolygon_boundary ( const ExPolygon & expoly , float samples_per_mm , std : : vector < Vec2f > & out , std : : mt19937 & rng ) ;
2019-11-11 10:41:14 +00:00
} } // namespace Slic3r::sla
2018-12-07 13:10:16 +00:00
2019-11-11 10:41:14 +00:00
# endif // SUPPORTPOINTGENERATOR_HPP