OrcaSlicer latest
OrcaSlicer
Loading...
Searching...
No Matches
Slic3r::sla::SupportPointGenerator Class Reference

#include </home/runner/work/OrcaSlicer/OrcaSlicer/src/libslic3r/SLA/SupportPointGenerator.hpp>

Collaboration diagram for Slic3r::sla::SupportPointGenerator:

Classes

struct  Config
struct  Structure
struct  MyLayer
struct  RichSupportPoint
struct  PointGrid3D

Public Types

enum  IslandCoverageFlags : uint8_t { icfNone = 0x0 , icfIsNew = 0x1 , icfWithBoundary = 0x2 }

Public Member Functions

 SupportPointGenerator (const IndexedMesh &emesh, const std::vector< ExPolygons > &slices, const std::vector< float > &heights, const Config &config, std::function< void(void)> throw_on_cancel, std::function< void(int)> statusfn)
 SupportPointGenerator (const IndexedMesh &emesh, const Config &config, std::function< void(void)> throw_on_cancel, std::function< void(int)> statusfn)
const std::vector< SupportPoint > & output () const
std::vector< SupportPoint > & output ()
void execute (const std::vector< ExPolygons > &slices, const std::vector< float > &heights)
void seed (std::mt19937::result_type s)

Private Member Functions

void process (const std::vector< ExPolygons > &slices, const std::vector< float > &heights)
void uniformly_cover (const ExPolygons &islands, Structure &structure, float deficit, PointGrid3D &grid3d, IslandCoverageFlags flags=icfNone)
void add_support_points (Structure &structure, PointGrid3D &grid3d)
void project_onto_mesh (std::vector< SupportPoint > &points) const

Private Attributes

std::vector< SupportPoint > m_output
SupportPointGenerator::Config m_config
const IndexedMesh & m_emesh
std::function< void(void)> m_throw_on_cancel
std::function< void(int)> m_statusfn
std::mt19937 m_rng

Detailed Description


Class Documentation

◆ Slic3r::sla::SupportPointGenerator::RichSupportPoint

struct Slic3r::sla::SupportPointGenerator::RichSupportPoint
Collaboration diagram for Slic3r::sla::SupportPointGenerator::RichSupportPoint:
Class Members
Structure * island
Vec3f position

Member Enumeration Documentation

◆ IslandCoverageFlags

Enumerator
icfNone 
icfIsNew 
icfWithBoundary 
216: uint8_t { icfNone = 0x0, icfIsNew = 0x1, icfWithBoundary = 0x2 };
@ icfIsNew
Definition SupportPointGenerator.hpp:216
@ icfNone
Definition SupportPointGenerator.hpp:216
@ icfWithBoundary
Definition SupportPointGenerator.hpp:216

Constructor & Destructor Documentation

◆ SupportPointGenerator() [1/2]

Slic3r::sla::SupportPointGenerator::SupportPointGenerator ( const IndexedMesh & emesh,
const std::vector< ExPolygons > & slices,
const std::vector< float > & heights,
const Config & config,
std::function< void(void)> throw_on_cancel,
std::function< void(int)> statusfn )
76 : SupportPointGenerator(emesh, config, throw_on_cancel, statusfn)
77{
78 std::random_device rd;
79 m_rng.seed(rd());
80 execute(slices, heights);
81}
void execute(const std::vector< ExPolygons > &slices, const std::vector< float > &heights)
Definition SupportPointGenerator.cpp:95
std::mt19937 m_rng
Definition SupportPointGenerator.hpp:235
SupportPointGenerator(const IndexedMesh &emesh, const std::vector< ExPolygons > &slices, const std::vector< float > &heights, const Config &config, std::function< void(void)> throw_on_cancel, std::function< void(int)> statusfn)
Definition SupportPointGenerator.cpp:69

References SupportPointGenerator(), execute(), and m_rng.

Referenced by SupportPointGenerator().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ SupportPointGenerator() [2/2]

Slic3r::sla::SupportPointGenerator::SupportPointGenerator ( const IndexedMesh & emesh,
const Config & config,
std::function< void(void)> throw_on_cancel,
std::function< void(int)> statusfn )

Member Function Documentation

◆ add_support_points()

void Slic3r::sla::SupportPointGenerator::add_support_points ( SupportPointGenerator::Structure & s,
SupportPointGenerator::PointGrid3D & grid3d )
private
312{
313 // Select each type of surface (overrhang, dangling, slope), derive the support
314 // force deficit for it and call uniformly conver with the right params
315
316 float tp = m_config.tear_pressure();
317 float current = s.supports_force_total();
318
319 if (s.islands_below.empty()) {
320 // completely new island - needs support no doubt
321 // deficit is full, there is nothing below that would hold this island
322 uniformly_cover({ *s.polygon }, s, s.area * tp, grid3d, IslandCoverageFlags(icfIsNew | icfWithBoundary) );
323 return;
324 }
325
326 if (! s.overhangs.empty()) {
327 uniformly_cover(s.overhangs, s, s.overhangs_area * tp, grid3d);
328 }
329
330 auto areafn = [](double sum, auto &p) { return sum + p.area() * SCALING_FACTOR * SCALING_FACTOR; };
331
332 current = s.supports_force_total();
333 if (! s.dangling_areas.empty()) {
334 // Let's see if there's anything that overlaps enough to need supports:
335 // What we now have in polygons needs support, regardless of what the forces are, so we can add them.
336
337 double a = std::accumulate(s.dangling_areas.begin(), s.dangling_areas.end(), 0., areafn);
338 uniformly_cover(s.dangling_areas, s, a * tp - a * current * s.area, grid3d, icfWithBoundary);
339 }
340
341 current = s.supports_force_total();
342 if (! s.overhangs_slopes.empty()) {
343 double a = std::accumulate(s.overhangs_slopes.begin(), s.overhangs_slopes.end(), 0., areafn);
344 uniformly_cover(s.overhangs_slopes, s, a * tp - a * current / s.area, grid3d, icfWithBoundary);
345 }
346}
void uniformly_cover(const ExPolygons &islands, Structure &structure, float deficit, PointGrid3D &grid3d, IslandCoverageFlags flags=icfNone)
Definition SupportPointGenerator.cpp:559
IslandCoverageFlags
Definition SupportPointGenerator.hpp:216
SupportPointGenerator::Config m_config
Definition SupportPointGenerator.hpp:211
double SCALING_FACTOR
Definition libslic3r.cpp:3

References add_support_points(), Slic3r::sla::SupportPointGenerator::Structure::area, Slic3r::sla::SupportPointGenerator::Structure::dangling_areas, icfIsNew, icfWithBoundary, Slic3r::sla::SupportPointGenerator::Structure::islands_below, m_config, Slic3r::sla::SupportPointGenerator::Structure::overhangs, Slic3r::sla::SupportPointGenerator::Structure::overhangs_area, Slic3r::sla::SupportPointGenerator::Structure::overhangs_slopes, Slic3r::sla::SupportPointGenerator::Structure::polygon, SCALING_FACTOR, Slic3r::sla::SupportPointGenerator::Structure::supports_force_total(), and uniformly_cover().

Referenced by add_support_points(), and process().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ execute()

void Slic3r::sla::SupportPointGenerator::execute ( const std::vector< ExPolygons > & slices,
const std::vector< float > & heights )
97{
98 process(slices, heights);
100}
std::vector< SupportPoint > m_output
Definition SupportPointGenerator.hpp:209
void process(const std::vector< ExPolygons > &slices, const std::vector< float > &heights)
Definition SupportPointGenerator.cpp:241
void project_onto_mesh(std::vector< SupportPoint > &points) const
Definition SupportPointGenerator.cpp:102

References m_output, process(), and project_onto_mesh().

Referenced by SupportPointGenerator().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ output() [1/2]

std::vector< SupportPoint > & Slic3r::sla::SupportPointGenerator::output ( )
inline
48{ return m_output; }

References m_output.

◆ output() [2/2]

const std::vector< SupportPoint > & Slic3r::sla::SupportPointGenerator::output ( ) const
inline
47{ return m_output; }

References m_output.

Referenced by Slic3r::SLAPrint::Steps::support_points().

Here is the caller graph for this function:

◆ process()

void Slic3r::sla::SupportPointGenerator::process ( const std::vector< ExPolygons > & slices,
const std::vector< float > & heights )
private
242{
243#ifdef SLA_SUPPORTPOINTGEN_DEBUG
244 std::vector<std::pair<ExPolygon, coord_t>> islands;
245#endif /* SLA_SUPPORTPOINTGEN_DEBUG */
246
247 std::vector<SupportPointGenerator::MyLayer> layers = make_layers(slices, heights, m_throw_on_cancel);
248
249 PointGrid3D point_grid;
250 point_grid.cell_size = Vec3f(10.f, 10.f, 10.f);
251
252 double increment = 100.0 / layers.size();
253 double status = 0;
254
255 for (unsigned int layer_id = 0; layer_id < layers.size(); ++ layer_id) {
256 SupportPointGenerator::MyLayer *layer_top = &layers[layer_id];
257 SupportPointGenerator::MyLayer *layer_bottom = (layer_id > 0) ? &layers[layer_id - 1] : nullptr;
258 std::vector<float> support_force_bottom;
259 if (layer_bottom != nullptr) {
260 support_force_bottom.assign(layer_bottom->islands.size(), 0.f);
261 for (size_t i = 0; i < layer_bottom->islands.size(); ++ i)
262 support_force_bottom[i] = layer_bottom->islands[i].supports_force_total();
263 }
264 for (Structure &top : layer_top->islands)
265 for (Structure::Link &bottom_link : top.islands_below) {
266 Structure &bottom = *bottom_link.island;
267 //float centroids_dist = (bottom.centroid - top.centroid).norm();
268 // Penalization resulting from centroid offset:
269// bottom.supports_force *= std::min(1.f, 1.f - std::min(1.f, (1600.f * layer_height) * centroids_dist * centroids_dist / bottom.area));
270 float &support_force = support_force_bottom[&bottom - layer_bottom->islands.data()];
271//FIXME this condition does not reflect a bifurcation into a one large island and one tiny island well, it incorrectly resets the support force to zero.
272// One should rather work with the overlap area vs overhang area.
273// support_force *= std::min(1.f, 1.f - std::min(1.f, 0.1f * centroids_dist * centroids_dist / bottom.area));
274 // Penalization resulting from increasing polygon area:
275 support_force *= std::min(1.f, 20.f * bottom.area / top.area);
276 }
277 // Let's assign proper support force to each of them:
278 if (layer_id > 0) {
279 for (Structure &below : layer_bottom->islands) {
280 float below_support_force = support_force_bottom[&below - layer_bottom->islands.data()];
281 float above_overlap_area = 0.f;
282 for (Structure::Link &above_link : below.islands_above)
283 above_overlap_area += above_link.overlap_area;
284 for (Structure::Link &above_link : below.islands_above)
285 above_link.island->supports_force_inherited += below_support_force * above_link.overlap_area / above_overlap_area;
286 }
287 }
288 // Now iterate over all polygons and append new points if needed.
289 for (Structure &s : layer_top->islands) {
290 // Penalization resulting from large diff from the last layer:
291 s.supports_force_inherited /= std::max(1.f, 0.17f * (s.overhangs_area) / s.area);
292
293 add_support_points(s, point_grid);
294 }
295
297
298 status += increment;
299 m_statusfn(int(std::round(status)));
300
301#ifdef SLA_SUPPORTPOINTGEN_DEBUG
302 /*std::string layer_num_str = std::string((i<10 ? "0" : "")) + std::string((i<100 ? "0" : "")) + std::to_string(i);
303 output_expolygons(expolys_top, "top" + layer_num_str + ".svg");
304 output_expolygons(diff, "diff" + layer_num_str + ".svg");
305 if (!islands.empty())
306 output_expolygons(islands, "islands" + layer_num_str + ".svg");*/
307#endif /* SLA_SUPPORTPOINTGEN_DEBUG */
308 }
309}
std::function< void(int)> m_statusfn
Definition SupportPointGenerator.hpp:233
void add_support_points(Structure &structure, PointGrid3D &grid3d)
Definition SupportPointGenerator.cpp:311
std::function< void(void)> m_throw_on_cancel
Definition SupportPointGenerator.hpp:232
static std::vector< SupportPointGenerator::MyLayer > make_layers(const std::vector< ExPolygons > &slices, const std::vector< float > &heights, std::function< void(void)> throw_on_cancel)
Definition SupportPointGenerator.cpp:131
Eigen::Matrix< float, 3, 1, Eigen::DontAlign > Vec3f
Definition Point.hpp:65
Definition SupportPointGenerator.hpp:151
Vec3f cell_size
Definition SupportPointGenerator.hpp:159
Definition SupportPointGenerator.hpp:52

References add_support_points(), Slic3r::sla::SupportPointGenerator::Structure::area, Slic3r::sla::SupportPointGenerator::PointGrid3D::cell_size, Slic3r::sla::SupportPointGenerator::Structure::Link::island, Slic3r::sla::SupportPointGenerator::MyLayer::islands, Slic3r::sla::SupportPointGenerator::Structure::islands_above, Slic3r::sla::SupportPointGenerator::Structure::islands_below, m_statusfn, m_throw_on_cancel, Slic3r::sla::make_layers(), Slic3r::sla::SupportPointGenerator::Structure::overhangs_area, Slic3r::sla::SupportPointGenerator::Structure::Link::overlap_area, process(), and Slic3r::sla::SupportPointGenerator::Structure::supports_force_inherited.

Referenced by execute(), and process().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ project_onto_mesh()

void Slic3r::sla::SupportPointGenerator::project_onto_mesh ( std::vector< SupportPoint > & points) const
private
103{
104 // The function makes sure that all the points are really exactly placed on the mesh.
105
106 // Use a reasonable granularity to account for the worker thread synchronization cost.
107 static constexpr size_t gransize = 64;
108
109 ccr_par::for_each(size_t(0), points.size(), [this, &points](size_t idx)
110 {
111 if ((idx % 16) == 0)
112 // Don't call the following function too often as it flushes CPU write caches due to synchronization primitves.
113 m_throw_on_cancel();
114
115 Vec3f& p = points[idx].pos;
116 // Project the point upward and downward and choose the closer intersection with the mesh.
117 sla::IndexedMesh::hit_result hit_up = m_emesh.query_ray_hit(p.cast<double>(), Vec3d(0., 0., 1.));
118 sla::IndexedMesh::hit_result hit_down = m_emesh.query_ray_hit(p.cast<double>(), Vec3d(0., 0., -1.));
119
120 bool up = hit_up.is_hit();
121 bool down = hit_down.is_hit();
122
123 if (!up && !down)
124 return;
125
126 sla::IndexedMesh::hit_result& hit = (!down || (hit_up.distance() < hit_down.distance())) ? hit_up : hit_down;
127 p = p + (hit.distance() * hit.direction()).cast<float>();
128 }, gransize);
129}
static void for_each(It from, It to, Fn &&fn, size_t granularity=1)
Definition Concurrency.hpp:26

References Slic3r::sla::_ccr< true >::for_each().

Referenced by execute().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ seed()

void Slic3r::sla::SupportPointGenerator::seed ( std::mt19937::result_type s)
inline
207{ m_rng.seed(s); }

References m_rng.

◆ uniformly_cover()

void Slic3r::sla::SupportPointGenerator::uniformly_cover ( const ExPolygons & islands,
Structure & structure,
float deficit,
PointGrid3D & grid3d,
IslandCoverageFlags flags = icfNone )
private
560{
561 //int num_of_points = std::max(1, (int)((island.area()*pow(SCALING_FACTOR, 2) * m_config.tear_pressure)/m_config.support_force));
562
563 float support_force_deficit = deficit;
564// auto bb = get_extents(islands);
565
566 if (flags & icfIsNew) {
567 auto chull = Geometry::convex_hull(islands);
568 auto rotbox = MinAreaBoundigBox{chull, MinAreaBoundigBox::pcConvex};
569 Vec2d bbdim = {unscaled(rotbox.width()), unscaled(rotbox.height())};
570
571 if (bbdim.x() > bbdim.y()) std::swap(bbdim.x(), bbdim.y());
572 double aspectr = bbdim.y() / bbdim.x();
573
574 support_force_deficit *= (1 + aspectr / 2.);
575 }
576
577 if (support_force_deficit < 0)
578 return;
579
580 // Number of newly added points.
581 const size_t poisson_samples_target = size_t(ceil(support_force_deficit / m_config.support_force()));
582
583 const float density_horizontal = m_config.tear_pressure() / m_config.support_force();
584 //FIXME why?
585 float poisson_radius = std::max(m_config.minimal_distance, 1.f / (5.f * density_horizontal));
586// const float poisson_radius = 1.f / (15.f * density_horizontal);
587 const float samples_per_mm2 = 30.f / (float(M_PI) * poisson_radius * poisson_radius);
588 // Minimum distance between samples, in 3D space.
589// float min_spacing = poisson_radius / 3.f;
590 float min_spacing = poisson_radius;
591
592 //FIXME share the random generator. The random generator may be not so cheap to initialize, also we don't want the random generator to be restarted for each polygon.
593
594 std::vector<Vec2f> raw_samples =
595 flags & icfWithBoundary ?
596 sample_expolygon_with_boundary(islands, samples_per_mm2,
597 5.f / poisson_radius, m_rng) :
598 sample_expolygon(islands, samples_per_mm2, m_rng);
599
600 std::vector<Vec2f> poisson_samples;
601 for (size_t iter = 0; iter < 4; ++ iter) {
602 poisson_samples = poisson_disk_from_samples(raw_samples, poisson_radius,
603 [&structure, &grid3d, min_spacing](const Vec2f &pos) {
604 return grid3d.collides_with(pos, structure.layer->print_z, min_spacing);
605 });
606 if (poisson_samples.size() >= poisson_samples_target || m_config.minimal_distance > poisson_radius-EPSILON)
607 break;
608 float coeff = 0.5f;
609 if (poisson_samples.size() * 2 > poisson_samples_target)
610 coeff = float(poisson_samples.size()) / float(poisson_samples_target);
611 poisson_radius = std::max(m_config.minimal_distance, poisson_radius * coeff);
612 min_spacing = std::max(m_config.minimal_distance, min_spacing * coeff);
613 }
614
615#ifdef SLA_SUPPORTPOINTGEN_DEBUG
616 {
617 static int irun = 0;
618 Slic3r::SVG svg(debug_out_path("SLA_supports-uniformly_cover-%d.svg", irun ++), get_extents(islands));
619 for (const ExPolygon &island : islands)
620 svg.draw(island);
621 for (const Vec2f &pt : raw_samples)
622 svg.draw(Point(scale_(pt.x()), scale_(pt.y())), "red");
623 for (const Vec2f &pt : poisson_samples)
624 svg.draw(Point(scale_(pt.x()), scale_(pt.y())), "blue");
625 }
626#endif /* NDEBUG */
627
628// assert(! poisson_samples.empty());
629 if (poisson_samples_target < poisson_samples.size()) {
630 std::shuffle(poisson_samples.begin(), poisson_samples.end(), m_rng);
631 poisson_samples.erase(poisson_samples.begin() + poisson_samples_target, poisson_samples.end());
632 }
633 for (const Vec2f &pt : poisson_samples) {
634 m_output.emplace_back(float(pt(0)), float(pt(1)), structure.zlevel, m_config.head_diameter/2.f, flags & icfIsNew);
635 structure.supports_force_this_layer += m_config.support_force();
636 grid3d.insert(pt, &structure);
637 }
638}
#define EPSILON
Definition ColorUtils.cpp:64
#define M_PI
Definition ExtrusionSimulator.cpp:31
@ pcConvex
Definition MinAreaBoundingBox.hpp:25
#define scale_(val)
Definition libslic3r.h:106
Polygon convex_hull(Points pts)
Definition ConvexHull.cpp:21
Kernel::Point_3 Point
Definition MeshRepair.cpp:81
Vec3d pos(const Pt &p)
Definition ReprojectPointsOnMesh.hpp:16
std::vector< Vec2f > sample_expolygon_with_boundary(const ExPolygon &expoly, float samples_per_mm2, float samples_per_mm_boundary, std::mt19937 &rng)
Definition SupportPointGenerator.cpp:428
std::vector< Vec2f > sample_expolygon(const ExPolygon &expoly, float samples_per_mm2, std::mt19937 &rng)
Definition SupportPointGenerator.cpp:348
static std::vector< Vec2f > poisson_disk_from_samples(const std::vector< Vec2f > &raw_samples, float radius, REFUSE_FUNCTION refuse_function)
Definition SupportPointGenerator.cpp:444
std::string debug_out_path(const char *name,...)
Definition utils.cpp:382
BoundingBox get_extents(const ExPolygonsWithIds &e)
Definition Emboss.cpp:1374
constexpr Eigen::Matrix< Tout, 2, EigenArgs... > unscaled(const Slic3r::Point &v) noexcept
Definition Arrange.cpp:81
Eigen::Matrix< float, 2, 1, Eigen::DontAlign > Vec2f
Definition Point.hpp:64
Eigen::Matrix< double, 2, 1, Eigen::DontAlign > Vec2d
Definition Point.hpp:67

References Slic3r::sla::SupportPointGenerator::PointGrid3D::collides_with(), Slic3r::Geometry::convex_hull(), Slic3r::debug_out_path(), Slic3r::SVG::draw(), EPSILON, Slic3r::get_extents(), icfIsNew, icfWithBoundary, Slic3r::sla::SupportPointGenerator::PointGrid3D::insert(), Slic3r::sla::SupportPointGenerator::Structure::layer, m_config, m_output, M_PI, m_rng, Slic3r::MinAreaBoundigBox::pcConvex, Slic3r::sla::poisson_disk_from_samples(), Slic3r::sla::pos(), Slic3r::sla::SupportPointGenerator::MyLayer::print_z, Slic3r::sla::sample_expolygon(), Slic3r::sla::sample_expolygon_with_boundary(), scale_, Slic3r::sla::SupportPointGenerator::Structure::supports_force_this_layer, uniformly_cover(), Slic3r::unscaled(), and Slic3r::sla::SupportPointGenerator::Structure::zlevel.

Referenced by add_support_points(), and uniformly_cover().

Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ m_config

SupportPointGenerator::Config Slic3r::sla::SupportPointGenerator::m_config
private

◆ m_emesh

const IndexedMesh& Slic3r::sla::SupportPointGenerator::m_emesh
private

◆ m_output

std::vector<SupportPoint> Slic3r::sla::SupportPointGenerator::m_output
private

◆ m_rng

std::mt19937 Slic3r::sla::SupportPointGenerator::m_rng
private

◆ m_statusfn

std::function<void(int)> Slic3r::sla::SupportPointGenerator::m_statusfn
private

Referenced by process().

◆ m_throw_on_cancel

std::function<void(void)> Slic3r::sla::SupportPointGenerator::m_throw_on_cancel
private

Referenced by process().


The documentation for this class was generated from the following files: