2019-11-11 11:41:14 +01:00
#ifndef SLA_SUPPORTPOINTGENERATOR_HPP
#define SLA_SUPPORTPOINTGENERATOR_HPP
2020-01-15 17:44:15 +01:00
#include <random>
2019-11-11 11:41:14 +01:00
#include <libslic3r/SLA/SupportPoint.hpp>
2020-06-25 13:58:51 +02:00
#include <libslic3r/SLA/IndexedMesh.hpp>
2018-12-07 14:10:16 +01:00
2020-05-22 17:21:54 +02:00
#include <libslic3r/BoundingBox.hpp>
2019-02-20 11:16:31 +01:00
#include <libslic3r/ClipperUtils.hpp>
2018-12-07 14:10:16 +01:00
#include <libslic3r/Point.hpp>
2018-12-07 14:10:16 +01:00
2019-02-18 11:46:06 +01:00
#include <boost/container/small_vector.hpp>
2019-11-11 11:41:14 +01:00
// #define SLA_SUPPORTPOINTGEN_DEBUG
2018-12-07 14:10:16 +01:00
2019-11-11 11:41:14 +01:00
namespace Slic3r { namespace sla {
2018-12-07 14:10:16 +01:00
2019-11-11 11:41:14 +01:00
class SupportPointGenerator {
2018-12-07 14:10:16 +01:00
public :
struct Config {
2019-11-11 11:41:14 +01:00
float density_relative { 1.f };
float minimal_distance { 1.f };
float head_diameter { 0.4f };
2020-09-10 13:37:58 +02: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 11:41:14 +01:00
inline float tear_pressure () const { return 1.f ; } // pressure that the display exerts (the force unit per mm2)
};
2020-06-25 13:58:51 +02:00
SupportPointGenerator ( const IndexedMesh & emesh , const std :: vector < ExPolygons >& slices ,
2019-11-11 11:41:14 +01:00
const std :: vector < float >& heights , const Config & config , std :: function < void ( void ) > throw_on_cancel , std :: function < void ( int ) > statusfn );
2020-06-25 13:58:51 +02:00
SupportPointGenerator ( const IndexedMesh & emesh , const Config & config , std :: function < void ( void ) > throw_on_cancel , std :: function < void ( int ) > statusfn );
2020-01-13 13:57:39 +01:00
2020-01-14 10:41:42 +01:00
const std :: vector < SupportPoint >& output () const { return m_output ; }
std :: vector < SupportPoint >& output () { return m_output ; }
2019-11-11 11:41:14 +01:00
struct MyLayer ;
2019-09-24 15:15:49 +02:00
2019-01-30 08:26:23 +01:00
struct Structure {
2020-08-31 10:38:24 +02: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 11:41:14 +01:00
#ifdef SLA_SUPPORTPOINTGEN_DEBUG
2019-02-06 10:57:45 +01:00
, unique_id ( std :: chrono :: duration_cast < std :: chrono :: milliseconds > ( std :: chrono :: system_clock :: now (). time_since_epoch ()))
2019-11-11 11:41:14 +01:00
#endif /* SLA_SUPPORTPOINTGEN_DEBUG */
{}
2019-02-18 11:46:06 +01:00
MyLayer * layer ;
2019-01-30 08:26:23 +01:00
const ExPolygon * polygon = nullptr ;
2019-02-06 10:57:45 +01:00
const BoundingBox bbox ;
2019-02-06 11:09:00 +01:00
const Vec2f centroid = Vec2f :: Zero ();
2019-02-06 10:57:45 +01:00
const float area = 0.f ;
2020-08-31 10:38:24 +02:00
float zlevel = 0 ;
2019-02-06 10:57:45 +01:00
// How well is this ExPolygon held to the print base?
// Positive number, the higher the better.
2019-02-19 10:09:41 +01: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 11:41:14 +01:00
#ifdef SLA_SUPPORTPOINTGEN_DEBUG
2019-01-30 08:26:23 +01:00
std :: chrono :: milliseconds unique_id ;
2019-11-11 11:41:14 +01:00
#endif /* SLA_SUPPORTPOINTGEN_DEBUG */
2019-02-20 10:46:49 +01:00
struct Link {
2019-11-11 11:41:14 +01:00
Link ( Structure * island , float overlap_area ) : island ( island ), overlap_area ( overlap_area ) {}
2019-02-20 10:46:49 +01:00
Structure * island ;
float overlap_area ;
};
2019-02-19 10:09:41 +01:00
#ifdef NDEBUG
2019-11-11 11:41:14 +01:00
// In release mode, use the optimized container.
2019-02-20 10:46:49 +01:00
boost :: container :: small_vector < Link , 4 > islands_above ;
boost :: container :: small_vector < Link , 4 > islands_below ;
2019-02-19 10:09:41 +01:00
#else
2019-11-11 11:41:14 +01: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 10:09:41 +01:00
#endif
2019-02-27 08:49:09 +01:00
// Overhangs, that are dangling considerably.
2019-02-20 10:46:49 +01:00
ExPolygons dangling_areas ;
2019-02-27 08:49:09 +01:00
// Complete overhands.
2019-02-20 10:46:49 +01:00
ExPolygons overhangs ;
2019-02-27 08:49:09 +01:00
// Overhangs, where the surface must slope.
ExPolygons overhangs_slopes ;
2020-01-14 10:24:15 +01:00
float overhangs_area = 0.f ;
2019-11-11 11:41:14 +01:00
2019-02-20 10:46:49 +01:00
bool overlaps ( const Structure & rhs ) const {
2021-01-22 15:32:36 +01:00
//FIXME ExPolygon::overlaps() shall be commutative, it is not!
2019-02-20 10:46:49 +01:00
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 )) {
2021-05-05 12:16:40 +02:00
Polygons polys = intersection ( * this -> polygon , * rhs . polygon );
2019-11-11 11:41:14 +01:00
for ( const Polygon & poly : polys )
2019-02-20 10:46:49 +01:00
out += poly . area ();
}
return float ( out );
}
2019-02-06 10:57:45 +01:00
float area_below () const {
float area = 0.f ;
2019-02-20 10:46:49 +01:00
for ( const Link & below : this -> islands_below )
area += below . island -> area ;
2019-02-06 10:57:45 +01:00
return area ;
}
Polygons polygons_below () const {
size_t cnt = 0 ;
2019-11-11 11:41:14 +01:00
for ( const Link & below : this -> islands_below )
2019-02-20 10:46:49 +01:00
cnt += 1 + below . island -> polygon -> holes . size ();
2019-02-06 10:57:45 +01:00
Polygons out ;
out . reserve ( cnt );
2019-11-11 11:41:14 +01:00
for ( const Link & below : this -> islands_below ) {
2019-02-20 10:46:49 +01:00
out . emplace_back ( below . island -> polygon -> contour );
2019-11-11 11:41:14 +01:00
append ( out , below . island -> polygon -> holes );
2019-02-06 10:57:45 +01:00
}
return out ;
}
ExPolygons expolygons_below () const {
ExPolygons out ;
2019-02-18 11:46:06 +01:00
out . reserve ( this -> islands_below . size ());
2019-02-20 10:46:49 +01:00
for ( const Link & below : this -> islands_below )
out . emplace_back ( * below . island -> polygon );
2019-02-06 10:57:45 +01:00
return out ;
}
2019-02-19 10:09:41 +01: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 08:26:23 +01:00
};
2019-11-11 11:41:14 +01:00
2019-02-18 11:46:06 +01:00
struct MyLayer {
2019-11-11 11:41:14 +01:00
MyLayer ( const size_t layer_id , coordf_t print_z ) : layer_id ( layer_id ), print_z ( print_z ) {}
2019-02-18 11:46:06 +01:00
size_t layer_id ;
coordf_t print_z ;
std :: vector < Structure > islands ;
};
2019-11-11 11:41:14 +01:00
2019-02-18 11:46:06 +01:00
struct RichSupportPoint {
Vec3f position ;
Structure * island ;
};
2019-11-11 11:41:14 +01:00
2019-02-18 11:46:06 +01:00
struct PointGrid3D {
struct GridHash {
2019-02-18 12:47:15 +01:00
std :: size_t operator ()( const Vec3i & cell_id ) const {
2019-02-18 11:46:06 +01: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 11:41:14 +01:00
2019-02-18 11:46:06 +01:00
Vec3f cell_size ;
Grid grid ;
2019-11-11 11:41:14 +01:00
2019-02-18 11:46:06 +01: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 11:41:14 +01:00
2019-02-18 11:46:06 +01:00
void insert ( const Vec2f & pos , Structure * island ) {
RichSupportPoint pt ;
2019-11-11 11:41:14 +01:00
pt . position = Vec3f ( pos . x (), pos . y (), float ( island -> layer -> print_z ));
2019-02-18 11:46:06 +01:00
pt . island = island ;
grid . emplace ( cell_id ( pt . position ), pt );
}
2019-11-11 11:41:14 +01:00
2020-08-31 10:38:24 +02:00
bool collides_with ( const Vec2f & pos , float print_z , float radius ) {
Vec3f pos3d ( pos . x (), pos . y (), print_z );
2019-02-18 11:46:06 +01: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 11:41:14 +01:00
2019-02-18 11:46:06 +01: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 11:41:14 +01:00
float dist2 = ( it -> second . position - pos ). squaredNorm ();
2019-02-18 11:46:06 +01:00
if ( dist2 < radius * radius )
return true ;
}
return false ;
}
};
2019-11-11 11:41:14 +01:00
2020-01-13 13:57:39 +01:00
void execute ( const std :: vector < ExPolygons > & slices ,
const std :: vector < float > & heights );
2020-01-15 17:44:15 +01:00
void seed ( std :: mt19937 :: result_type s ) { m_rng . seed ( s ); }
2019-02-18 11:46:06 +01:00
private :
2019-11-11 11:41:14 +01:00
std :: vector < SupportPoint > m_output ;
SupportPointGenerator :: Config m_config ;
2020-01-15 17:44:15 +01:00
void process ( const std :: vector < ExPolygons >& slices , const std :: vector < float >& heights );
2020-08-31 10:38:24 +02:00
public :
2020-10-12 09:43:57 +02:00
enum IslandCoverageFlags : uint8_t { icfNone = 0x0 , icfIsNew = 0x1 , icfWithBoundary = 0x2 };
2020-08-31 10:38:24 +02:00
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 11:41:14 +01:00
void project_onto_mesh ( std :: vector < SupportPoint >& points ) const ;
2019-01-30 08:26:23 +01:00
2019-11-11 11:41:14 +01:00
#ifdef SLA_SUPPORTPOINTGEN_DEBUG
2019-02-06 10:57:45 +01:00
static void output_expolygons ( const ExPolygons & expolys , const std :: string & filename );
static void output_structures ( const std :: vector < Structure > & structures );
2019-11-11 11:41:14 +01:00
#endif // SLA_SUPPORTPOINTGEN_DEBUG
2020-06-25 13:58:51 +02:00
const IndexedMesh & m_emesh ;
2019-04-02 10:54:14 +02:00
std :: function < void ( void ) > m_throw_on_cancel ;
std :: function < void ( int ) > m_statusfn ;
2020-01-15 17:44:15 +01:00
std :: mt19937 m_rng ;
2018-12-07 14:10:16 +01:00
};
2020-06-02 17:28:46 +02:00
void remove_bottom_points ( std :: vector < SupportPoint > & pts , float lvl );
2018-12-07 14:10:16 +01:00
2020-08-31 10:38:24 +02: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 11:41:14 +01:00
}} // namespace Slic3r::sla
2018-12-07 14:10:16 +01:00
2019-11-11 11:41:14 +01:00
#endif // SUPPORTPOINTGENERATOR_HPP