Prusa Slicer 2.6.0
Loading...
Searching...
No Matches
Slic3r::PrintObjectSupportMaterial Class Reference

#include <src/libslic3r/Support/SupportMaterial.hpp>

+ Collaboration diagram for Slic3r::PrintObjectSupportMaterial:

Public Member Functions

 PrintObjectSupportMaterial (const PrintObject *object, const SlicingParameters &slicing_params)
 
bool has_raft () const
 
bool has_support () const
 
bool build_plate_only () const
 
bool synchronize_layers () const
 
bool has_contact_loops () const
 
void generate (PrintObject &object)
 

Private Types

using SupportGeneratorLayersPtr = FFFSupport::SupportGeneratorLayersPtr
 
using SupportGeneratorLayerStorage = FFFSupport::SupportGeneratorLayerStorage
 
using SupportParameters = FFFSupport::SupportParameters
 

Private Member Functions

std::vector< Polygonsbuildplate_covered (const PrintObject &object) const
 
SupportGeneratorLayersPtr top_contact_layers (const PrintObject &object, const std::vector< Polygons > &buildplate_covered, SupportGeneratorLayerStorage &layer_storage) const
 
SupportGeneratorLayersPtr bottom_contact_layers_and_layer_support_areas (const PrintObject &object, const SupportGeneratorLayersPtr &top_contacts, std::vector< Polygons > &buildplate_covered, SupportGeneratorLayerStorage &layer_storage, std::vector< Polygons > &layer_support_areas) const
 
void trim_top_contacts_by_bottom_contacts (const PrintObject &object, const SupportGeneratorLayersPtr &bottom_contacts, SupportGeneratorLayersPtr &top_contacts) const
 
SupportGeneratorLayersPtr raft_and_intermediate_support_layers (const PrintObject &object, const SupportGeneratorLayersPtr &bottom_contacts, const SupportGeneratorLayersPtr &top_contacts, SupportGeneratorLayerStorage &layer_storage) const
 
void generate_base_layers (const PrintObject &object, const SupportGeneratorLayersPtr &bottom_contacts, const SupportGeneratorLayersPtr &top_contacts, SupportGeneratorLayersPtr &intermediate_layers, const std::vector< Polygons > &layer_support_areas) const
 
void trim_support_layers_by_object (const PrintObject &object, SupportGeneratorLayersPtr &support_layers, const coordf_t gap_extra_above, const coordf_t gap_extra_below, const coordf_t gap_xy) const
 

Private Attributes

const PrintConfig * m_print_config
 
const PrintObjectConfigm_object_config
 
SlicingParameters m_slicing_params
 
SupportParameters m_support_params
 

Detailed Description

Member Typedef Documentation

◆ SupportGeneratorLayersPtr

◆ SupportGeneratorLayerStorage

◆ SupportParameters

Constructor & Destructor Documentation

◆ PrintObjectSupportMaterial()

Slic3r::PrintObjectSupportMaterial::PrintObjectSupportMaterial ( const PrintObject object,
const SlicingParameters slicing_params 
)
231 :
232 m_print_config (&object->print()->config()),
233 m_object_config (&object->config()),
234 m_slicing_params (slicing_params),
235 m_support_params (*object)
236{
237}
const PrintConfig * m_print_config
Definition SupportMaterial.hpp:90
SlicingParameters m_slicing_params
Definition SupportMaterial.hpp:94
const PrintObjectConfig * m_object_config
Definition SupportMaterial.hpp:91
SupportParameters m_support_params
Definition SupportMaterial.hpp:96

Member Function Documentation

◆ bottom_contact_layers_and_layer_support_areas()

SupportGeneratorLayersPtr Slic3r::PrintObjectSupportMaterial::bottom_contact_layers_and_layer_support_areas ( const PrintObject object,
const SupportGeneratorLayersPtr top_contacts,
std::vector< Polygons > &  buildplate_covered,
SupportGeneratorLayerStorage layer_storage,
std::vector< Polygons > &  layer_support_areas 
) const
private
1937{
1938 if (top_contacts.empty())
1940
1941#ifdef SLIC3R_DEBUG
1942 static size_t s_iRun = 0;
1943 size_t iRun = s_iRun ++;
1944#endif /* SLIC3R_DEBUG */
1945
1946 //FIXME higher expansion_to_slice here? why?
1947 //const auto expansion_to_slice = m_support_material_flow.scaled_spacing() / 2 + 25;
1948 const SupportGridParams grid_params(*m_object_config, m_support_params.support_material_flow);
1949 const bool buildplate_only = ! buildplate_covered.empty();
1950
1951 // Allocate empty surface areas, one per object layer.
1952 layer_support_areas.assign(object.total_layer_count(), Polygons());
1953
1954 // find object top surfaces
1955 // we'll use them to clip our support and detect where does it stick
1956 SupportGeneratorLayersPtr bottom_contacts;
1957
1958 // There is some support to be built, if there are non-empty top surfaces detected.
1959 // Sum of unsupported contact areas above the current layer.print_z.
1960 Polygons overhangs_projection;
1961 // Sum of unsupported enforcer contact areas above the current layer.print_z.
1962 // Only used if "supports on build plate only" is enabled and both automatic and support enforcers are enabled.
1963 Polygons enforcers_projection;
1964 // Last top contact layer visited when collecting the projection of contact areas.
1965 int contact_idx = int(top_contacts.size()) - 1;
1966 for (int layer_id = int(object.total_layer_count()) - 2; layer_id >= 0; -- layer_id) {
1967 BOOST_LOG_TRIVIAL(trace) << "Support generator - bottom_contact_layers - layer " << layer_id;
1968 const Layer &layer = *object.get_layer(layer_id);
1969 // Collect projections of all contact areas above or at the same level as this top surface.
1970#ifdef SLIC3R_DEBUG
1971 Polygons polygons_new;
1972 Polygons enforcers_new;
1973#endif // SLIC3R_DEBUG
1974 for (; contact_idx >= 0 && top_contacts[contact_idx]->print_z > layer.print_z - EPSILON; -- contact_idx) {
1975 SupportGeneratorLayer &top_contact = *top_contacts[contact_idx];
1976#ifndef SLIC3R_DEBUG
1977 Polygons polygons_new;
1978 Polygons enforcers_new;
1979#endif // SLIC3R_DEBUG
1980 // Contact surfaces are expanded away from the object, trimmed by the object.
1981 // Use a slight positive offset to overlap the touching regions.
1982#if 0
1983 // Merge and collect the contact polygons. The contact polygons are inflated, but not extended into a grid form.
1984 polygons_append(polygons_new, offset(*top_contact.contact_polygons, SCALED_EPSILON));
1985 if (top_contact.enforcer_polygons)
1986 polygons_append(enforcers_new, offset(*top_contact.enforcer_polygons, SCALED_EPSILON));
1987#else
1988 // Consume the contact_polygons. The contact polygons are already expanded into a grid form, and they are a tiny bit smaller
1989 // than the grid cells.
1990 polygons_append(polygons_new, std::move(*top_contact.contact_polygons));
1991 if (top_contact.enforcer_polygons)
1992 polygons_append(enforcers_new, std::move(*top_contact.enforcer_polygons));
1993#endif
1994 // These are the overhang surfaces. They are touching the object and they are not expanded away from the object.
1995 // Use a slight positive offset to overlap the touching regions.
1996 polygons_append(polygons_new, expand(*top_contact.overhang_polygons, float(SCALED_EPSILON)));
1997 polygons_append(overhangs_projection, union_(polygons_new));
1998 polygons_append(enforcers_projection, enforcers_new);
1999 }
2000 if (overhangs_projection.empty() && enforcers_projection.empty())
2001 continue;
2002
2003 // Overhangs_projection will be filled in asynchronously, move it away.
2004 Polygons overhangs_projection_raw = union_(std::move(overhangs_projection));
2005 Polygons enforcers_projection_raw = union_(std::move(enforcers_projection));
2006
2007 tbb::task_group task_group;
2008 const Polygons &overhangs_for_bottom_contacts = buildplate_only ? enforcers_projection_raw : overhangs_projection_raw;
2009 if (! overhangs_for_bottom_contacts.empty())
2010 // Find the bottom contact layers above the top surfaces of this layer.
2011 task_group.run([this, &object, &layer, &top_contacts, contact_idx, &layer_storage, &layer_support_areas, &bottom_contacts, &overhangs_for_bottom_contacts
2012 #ifdef SLIC3R_DEBUG
2013 , iRun, &polygons_new
2014 #endif // SLIC3R_DEBUG
2015 ] {
2016 // Find the bottom contact layers above the top surfaces of this layer.
2018 m_slicing_params, m_support_params, object, layer, top_contacts, contact_idx, layer_storage, layer_support_areas, overhangs_for_bottom_contacts
2019#ifdef SLIC3R_DEBUG
2020 , iRun, polygons_new
2021#endif // SLIC3R_DEBUG
2022 );
2023 if (layer_new)
2024 bottom_contacts.push_back(layer_new);
2025 });
2026
2027 Polygons &layer_support_area = layer_support_areas[layer_id];
2028 Polygons *layer_buildplate_covered = buildplate_covered.empty() ? nullptr : &buildplate_covered[layer_id];
2029 // Filtering the propagated support columns to two extrusions, overlapping by maximum 20%.
2030// float column_propagation_filtering_radius = scaled<float>(0.8 * 0.5 * (m_support_params.support_material_flow.spacing() + m_support_params.support_material_flow.width()));
2031 task_group.run([&grid_params, &overhangs_projection, &overhangs_projection_raw, &layer, &layer_support_area, layer_buildplate_covered /* , column_propagation_filtering_radius */
2032#ifdef SLIC3R_DEBUG
2033 , iRun, layer_id
2034#endif /* SLIC3R_DEBUG */
2035 ] {
2036 // buildplate_covered[layer_id] will be consumed here.
2037 std::tie(layer_support_area, overhangs_projection) = project_support_to_grid(layer, grid_params, overhangs_projection_raw, layer_buildplate_covered
2038#ifdef SLIC3R_DEBUG
2039 , iRun, layer_id, "general"
2040#endif /* SLIC3R_DEBUG */
2041 );
2042 // When propagating support areas downwards, stop propagating the support column if it becomes too thin to be printable.
2043 //overhangs_projection = opening(overhangs_projection, column_propagation_filtering_radius);
2044 });
2045
2046 Polygons layer_support_area_enforcers;
2047 if (! enforcers_projection.empty())
2048 // Project the enforcers polygons downwards, don't trim them with the "buildplate only" polygons.
2049 task_group.run([&grid_params, &enforcers_projection, &enforcers_projection_raw, &layer, &layer_support_area_enforcers
2050#ifdef SLIC3R_DEBUG
2051 , iRun, layer_id
2052#endif /* SLIC3R_DEBUG */
2053 ]{
2054 std::tie(layer_support_area_enforcers, enforcers_projection) = project_support_to_grid(layer, grid_params, enforcers_projection_raw, nullptr
2055#ifdef SLIC3R_DEBUG
2056 , iRun, layer_id, "enforcers"
2057#endif /* SLIC3R_DEBUG */
2058 );
2059 });
2060
2061 task_group.wait();
2062
2063 if (! layer_support_area_enforcers.empty()) {
2064 if (layer_support_area.empty())
2065 layer_support_area = std::move(layer_support_area_enforcers);
2066 else
2067 layer_support_area = union_(layer_support_area, layer_support_area_enforcers);
2068 }
2069 } // over all layers downwards
2070
2071 std::reverse(bottom_contacts.begin(), bottom_contacts.end());
2073 return bottom_contacts;
2074}
Definition SupportLayer.hpp:41
std::unique_ptr< Polygons > enforcer_polygons
Definition SupportLayer.hpp:112
std::unique_ptr< Polygons > contact_polygons
Definition SupportLayer.hpp:109
std::unique_ptr< Polygons > overhang_polygons
Definition SupportLayer.hpp:110
std::vector< Polygons > buildplate_covered(const PrintObject &object) const
Definition SupportMaterial.cpp:1062
FFFSupport::SupportGeneratorLayersPtr SupportGeneratorLayersPtr
Definition SupportMaterial.hpp:39
void trim_support_layers_by_object(const PrintObject &object, SupportGeneratorLayersPtr &support_layers, const coordf_t gap_extra_above, const coordf_t gap_extra_below, const coordf_t gap_xy) const
Definition SupportMaterial.cpp:2445
#define SCALED_EPSILON
Definition libslic3r.h:71
static constexpr double EPSILON
Definition libslic3r.h:51
std::vector< SupportGeneratorLayer * > SupportGeneratorLayersPtr
Definition SupportLayer.hpp:142
std::vector< Polygon, PointsAllocator< Polygon > > Polygons
Definition Polygon.hpp:15
Slic3r::Polygons union_(const Slic3r::Polygons &subject)
Definition ClipperUtils.cpp:704
static std::pair< Polygons, Polygons > project_support_to_grid(const Layer &layer, const SupportGridParams &grid_params, const Polygons &overhangs, Polygons *layer_buildplate_covered)
Definition SupportMaterial.cpp:1853
Slic3r::Polygons expand(const Slic3r::Polygon &polygon, const float delta, ClipperLib::JoinType joinType=DefaultJoinType, double miterLimit=DefaultMiterLimit)
Definition ClipperUtils.hpp:363
Slic3r::Polygons offset(const Slic3r::Polygon &polygon, const float delta, ClipperLib::JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:416
void polygons_append(Polygons &dst, const ExPolygon &src)
Definition ExPolygon.hpp:375
static SupportGeneratorLayer * detect_bottom_contacts(const SlicingParameters &slicing_params, const SupportParameters &support_params, const PrintObject &object, const Layer &layer, const SupportGeneratorLayersPtr &top_contacts, size_t contact_idx, SupportGeneratorLayerStorage &layer_storage, std::vector< Polygons > &layer_support_areas, const Polygons &supports_projected)
Definition SupportMaterial.cpp:1727
Flow support_material_flow
Definition SupportParameters.hpp:45
coordf_t gap_xy
Definition SupportParameters.hpp:58
coordf_t gap_object_support
Definition Slicing.hpp:86
coordf_t gap_support_object
Definition Slicing.hpp:88

References Slic3r::FFFSupport::SupportGeneratorLayer::contact_polygons, Slic3r::detect_bottom_contacts(), Slic3r::FFFSupport::SupportGeneratorLayer::enforcer_polygons, EPSILON, Slic3r::expand(), Slic3r::FFFSupport::SupportGeneratorLayer::overhang_polygons, Slic3r::polygons_append(), Slic3r::Layer::print_z, Slic3r::project_support_to_grid(), SCALED_EPSILON, and Slic3r::union_().

Referenced by generate().

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

◆ build_plate_only()

bool Slic3r::PrintObjectSupportMaterial::build_plate_only ( ) const
inline
28{ return this->has_support() && m_object_config->support_material_buildplate_only.value; }
bool has_support() const
Definition SupportMaterial.hpp:27

References has_support(), and m_object_config.

Referenced by buildplate_covered().

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

◆ buildplate_covered()

std::vector< Polygons > Slic3r::PrintObjectSupportMaterial::buildplate_covered ( const PrintObject object) const
private
1063{
1064 // Build support on a build plate only? If so, then collect and union all the surfaces below the current layer.
1065 // Unfortunately this is an inherently serial process.
1066 const bool buildplate_only = this->build_plate_only();
1067 std::vector<Polygons> buildplate_covered;
1068 if (buildplate_only) {
1069 BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::buildplate_covered() - start";
1070 buildplate_covered.assign(object.layers().size(), Polygons());
1071 //FIXME prefix sum algorithm, parallelize it! Parallelization will also likely be more numerically stable.
1072 for (size_t layer_id = 1; layer_id < object.layers().size(); ++ layer_id) {
1073 const Layer &lower_layer = *object.layers()[layer_id-1];
1074 // Merge the new slices with the preceding slices.
1075 // Apply the safety offset to the newly added polygons, so they will connect
1076 // with the polygons collected before,
1077 // but don't apply the safety offset during the union operation as it would
1078 // inflate the polygons over and over.
1079 Polygons &covered = buildplate_covered[layer_id];
1080 covered = buildplate_covered[layer_id - 1];
1081 polygons_append(covered, offset(lower_layer.lslices, scale_(0.01)));
1082 covered = union_(covered);
1083 }
1084 BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::buildplate_covered() - end";
1085 }
1086 return buildplate_covered;
1087}
bool build_plate_only() const
Definition SupportMaterial.hpp:28
#define scale_(val)
Definition libslic3r.h:69
constexpr auto size(const C &c) -> decltype(c.size())
Definition span.hpp:183

References build_plate_only(), buildplate_covered(), Slic3r::Layer::lslices, Slic3r::offset(), Slic3r::polygons_append(), scale_, and Slic3r::union_().

Referenced by buildplate_covered(), and generate().

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

◆ generate()

void Slic3r::PrintObjectSupportMaterial::generate ( PrintObject object)
240{
241 BOOST_LOG_TRIVIAL(info) << "Support generator - Start";
242
243 coordf_t max_object_layer_height = 0.;
244 for (size_t i = 0; i < object.layer_count(); ++ i)
245 max_object_layer_height = std::max(max_object_layer_height, object.layers()[i]->height);
246
247 // Layer instances will be allocated by std::deque and they will be kept until the end of this function call.
248 // The layers will be referenced by various LayersPtr (of type std::vector<Layer*>)
249 SupportGeneratorLayerStorage layer_storage;
250
251 BOOST_LOG_TRIVIAL(info) << "Support generator - Creating top contacts";
252
253 // Per object layer projection of the object below the layer into print bed.
254 std::vector<Polygons> buildplate_covered = this->buildplate_covered(object);
255
256 // Determine the top contact surfaces of the support, defined as:
257 // contact = overhangs - clearance + margin
258 // This method is responsible for identifying what contact surfaces
259 // should the support material expose to the object in order to guarantee
260 // that it will be effective, regardless of how it's built below.
261 // If raft is to be generated, the 1st top_contact layer will contain the 1st object layer silhouette without holes.
262 SupportGeneratorLayersPtr top_contacts = this->top_contact_layers(object, buildplate_covered, layer_storage);
263 if (top_contacts.empty())
264 // Nothing is supported, no supports are generated.
265 return;
266
267#ifdef SLIC3R_DEBUG
268 static int iRun = 0;
269 iRun ++;
270 for (const SupportGeneratorLayer *layer : top_contacts)
271 Slic3r::SVG::export_expolygons(
272 debug_out_path("support-top-contacts-%d-%lf.svg", iRun, layer->print_z),
273 union_ex(layer->polygons));
274#endif /* SLIC3R_DEBUG */
275
276 BOOST_LOG_TRIVIAL(info) << "Support generator - Creating bottom contacts";
277
278 // Determine the bottom contact surfaces of the supports over the top surfaces of the object.
279 // Depending on whether the support is soluble or not, the contact layer thickness is decided.
280 // layer_support_areas contains the per object layer support areas. These per object layer support areas
281 // may get merged and trimmed by this->generate_base_layers() if the support layers are not synchronized with object layers.
282 std::vector<Polygons> layer_support_areas;
284 object, top_contacts, buildplate_covered,
285 layer_storage, layer_support_areas);
286
287#ifdef SLIC3R_DEBUG
288 for (size_t layer_id = 0; layer_id < object.layers().size(); ++ layer_id)
290 debug_out_path("support-areas-%d-%lf.svg", iRun, object.layers()[layer_id]->print_z),
291 union_ex(layer_support_areas[layer_id]));
292#endif /* SLIC3R_DEBUG */
293
294 BOOST_LOG_TRIVIAL(info) << "Support generator - Creating intermediate layers - indices";
295
296 // Allocate empty layers between the top / bottom support contact layers
297 // as placeholders for the base and intermediate support layers.
298 // The layers may or may not be synchronized with the object layers, depending on the configuration.
299 // For example, a single nozzle multi material printing will need to generate a waste tower, which in turn
300 // wastes less material, if there are as little tool changes as possible.
302 object, bottom_contacts, top_contacts, layer_storage);
303
305
306#ifdef SLIC3R_DEBUG
307 for (const SupportGeneratorLayer *layer : top_contacts)
308 Slic3r::SVG::export_expolygons(
309 debug_out_path("support-top-contacts-trimmed-by-object-%d-%lf.svg", iRun, layer->print_z),
310 union_ex(layer->polygons));
311#endif
312
313 BOOST_LOG_TRIVIAL(info) << "Support generator - Creating base layers";
314
315 // Fill in intermediate layers between the top / bottom support contact layers, trim them by the object.
316 this->generate_base_layers(object, bottom_contacts, top_contacts, intermediate_layers, layer_support_areas);
317
318#ifdef SLIC3R_DEBUG
319 for (SupportGeneratorLayersPtr::const_iterator it = intermediate_layers.begin(); it != intermediate_layers.end(); ++ it)
321 debug_out_path("support-base-layers-%d-%lf.svg", iRun, (*it)->print_z),
322 union_ex((*it)->polygons));
323#endif /* SLIC3R_DEBUG */
324
325 BOOST_LOG_TRIVIAL(info) << "Support generator - Trimming top contacts by bottom contacts";
326
327 // Because the top and bottom contacts are thick slabs, they may overlap causing over extrusion
328 // and unwanted strong bonds to the object.
329 // Rather trim the top contacts by their overlapping bottom contacts to leave a gap instead of over extruding
330 // top contacts over the bottom contacts.
331 this->trim_top_contacts_by_bottom_contacts(object, bottom_contacts, top_contacts);
332
333
334 BOOST_LOG_TRIVIAL(info) << "Support generator - Creating interfaces";
335
336 // Propagate top / bottom contact layers to generate interface layers
337 // and base interface layers (for soluble interface / non souble base only)
338 SupportGeneratorLayersPtr empty_layers;
339 auto [interface_layers, base_interface_layers] = FFFSupport::generate_interface_layers(
340 *m_object_config, m_support_params, bottom_contacts, top_contacts, empty_layers, empty_layers, intermediate_layers, layer_storage);
341
342 BOOST_LOG_TRIVIAL(info) << "Support generator - Creating raft";
343
344 // If raft is to be generated, the 1st top_contact layer will contain the 1st object layer silhouette with holes filled.
345 // There is also a 1st intermediate layer containing bases of support columns.
346 // Inflate the bases of the support columns and create the raft base under the object.
347 SupportGeneratorLayersPtr raft_layers = FFFSupport::generate_raft_base(object, m_support_params, m_slicing_params, top_contacts, interface_layers, base_interface_layers, intermediate_layers, layer_storage);
348
349#ifdef SLIC3R_DEBUG
350 for (const SupportGeneratorLayer *l : interface_layers)
351 Slic3r::SVG::export_expolygons(
352 debug_out_path("support-interface-layers-%d-%lf.svg", iRun, l->print_z),
353 union_ex(l->polygons));
354 for (const SupportGeneratorLayer *l : base_interface_layers)
355 Slic3r::SVG::export_expolygons(
356 debug_out_path("support-base-interface-layers-%d-%lf.svg", iRun, l->print_z),
357 union_ex(l->polygons));
358#endif // SLIC3R_DEBUG
359
360/*
361 // Clip with the pillars.
362 if (! shape.empty()) {
363 this->clip_with_shape(interface, shape);
364 this->clip_with_shape(base, shape);
365 }
366*/
367
368 BOOST_LOG_TRIVIAL(info) << "Support generator - Creating layers";
369
370// For debugging purposes, one may want to show only some of the support extrusions.
371// raft_layers.clear();
372// bottom_contacts.clear();
373// top_contacts.clear();
374// intermediate_layers.clear();
375// interface_layers.clear();
376
377#ifdef SLIC3R_DEBUG
378 SupportGeneratorLayersPtr layers_sorted =
379#endif // SLIC3R_DEBUG
380 generate_support_layers(object, raft_layers, bottom_contacts, top_contacts, intermediate_layers, interface_layers, base_interface_layers);
381
382 BOOST_LOG_TRIVIAL(info) << "Support generator - Generating tool paths";
383
384#if 0 // #ifdef SLIC3R_DEBUG
385 {
386 size_t layer_id = 0;
387 for (int i = 0; i < int(layers_sorted.size());) {
388 // Find the last layer with roughly the same print_z, find the minimum layer height of all.
389 // Due to the floating point inaccuracies, the print_z may not be the same even if in theory they should.
390 int j = i + 1;
391 coordf_t zmax = layers_sorted[i]->print_z + EPSILON;
392 bool empty = layers_sorted[i]->polygons.empty();
393 for (; j < layers_sorted.size() && layers_sorted[j]->print_z <= zmax; ++j)
394 if (!layers_sorted[j]->polygons.empty())
395 empty = false;
396 if (!empty) {
398 debug_out_path("support-%d-%lf-before.svg", iRun, layers_sorted[i]->print_z).c_str(),
399 layers_sorted.data() + i, j - i);
401 debug_out_path("support-w-fills-%d-%lf-before.svg", iRun, layers_sorted[i]->print_z).c_str(),
402 layers_sorted.data() + i, j - i,
403 *object.support_layers()[layer_id]);
404 ++layer_id;
405 }
406 i = j;
407 }
408 }
409#endif /* SLIC3R_DEBUG */
410
411 // Generate the actual toolpaths and save them into each layer.
412 generate_support_toolpaths(object.support_layers(), *m_object_config, m_support_params, m_slicing_params, raft_layers, bottom_contacts, top_contacts, intermediate_layers, interface_layers, base_interface_layers);
413
414#ifdef SLIC3R_DEBUG
415 {
416 size_t layer_id = 0;
417 for (int i = 0; i < int(layers_sorted.size());) {
418 // Find the last layer with roughly the same print_z, find the minimum layer height of all.
419 // Due to the floating point inaccuracies, the print_z may not be the same even if in theory they should.
420 int j = i + 1;
421 coordf_t zmax = layers_sorted[i]->print_z + EPSILON;
422 bool empty = layers_sorted[i]->polygons.empty();
423 for (; j < layers_sorted.size() && layers_sorted[j]->print_z <= zmax; ++j)
424 if (! layers_sorted[j]->polygons.empty())
425 empty = false;
426 if (! empty) {
428 debug_out_path("support-%d-%lf.svg", iRun, layers_sorted[i]->print_z).c_str(),
429 layers_sorted.data() + i, j - i);
431 debug_out_path("support-w-fills-%d-%lf.svg", iRun, layers_sorted[i]->print_z).c_str(),
432 layers_sorted.data() + i, j - i,
433 *object.support_layers()[layer_id]);
434 ++layer_id;
435 }
436 i = j;
437 }
438 }
439#endif /* SLIC3R_DEBUG */
440
441 BOOST_LOG_TRIVIAL(info) << "Support generator - End";
442}
SupportGeneratorLayersPtr bottom_contact_layers_and_layer_support_areas(const PrintObject &object, const SupportGeneratorLayersPtr &top_contacts, std::vector< Polygons > &buildplate_covered, SupportGeneratorLayerStorage &layer_storage, std::vector< Polygons > &layer_support_areas) const
Definition SupportMaterial.cpp:1934
SupportGeneratorLayersPtr top_contact_layers(const PrintObject &object, const std::vector< Polygons > &buildplate_covered, SupportGeneratorLayerStorage &layer_storage) const
Definition SupportMaterial.cpp:1643
SupportGeneratorLayersPtr raft_and_intermediate_support_layers(const PrintObject &object, const SupportGeneratorLayersPtr &bottom_contacts, const SupportGeneratorLayersPtr &top_contacts, SupportGeneratorLayerStorage &layer_storage) const
Definition SupportMaterial.cpp:2102
void generate_base_layers(const PrintObject &object, const SupportGeneratorLayersPtr &bottom_contacts, const SupportGeneratorLayersPtr &top_contacts, SupportGeneratorLayersPtr &intermediate_layers, const std::vector< Polygons > &layer_support_areas) const
Definition SupportMaterial.cpp:2292
void trim_top_contacts_by_bottom_contacts(const PrintObject &object, const SupportGeneratorLayersPtr &bottom_contacts, SupportGeneratorLayersPtr &top_contacts) const
Definition SupportMaterial.cpp:2077
static void export_expolygons(const char *path, const BoundingBox &bbox, const Slic3r::ExPolygons &expolygons, std::string stroke_outer="black", std::string stroke_holes="blue", coordf_t stroke_width=0)
Definition SVG.cpp:309
double coordf_t
Definition libslic3r.h:45
void generate_support_toolpaths(SupportLayerPtrs &support_layers, const PrintObjectConfig &config, const SupportParameters &support_params, const SlicingParameters &slicing_params, const SupportGeneratorLayersPtr &raft_layers, const SupportGeneratorLayersPtr &bottom_contacts, const SupportGeneratorLayersPtr &top_contacts, const SupportGeneratorLayersPtr &intermediate_layers, const SupportGeneratorLayersPtr &interface_layers, const SupportGeneratorLayersPtr &base_interface_layers)
Definition SupportCommon.cpp:1458
SupportGeneratorLayersPtr generate_support_layers(PrintObject &object, const SupportGeneratorLayersPtr &raft_layers, const SupportGeneratorLayersPtr &bottom_contacts, const SupportGeneratorLayersPtr &top_contacts, const SupportGeneratorLayersPtr &intermediate_layers, const SupportGeneratorLayersPtr &interface_layers, const SupportGeneratorLayersPtr &base_interface_layers)
Definition SupportCommon.cpp:1381
SupportGeneratorLayersPtr generate_raft_base(const PrintObject &object, const SupportParameters &support_params, const SlicingParameters &slicing_params, const SupportGeneratorLayersPtr &top_contacts, const SupportGeneratorLayersPtr &interface_layers, const SupportGeneratorLayersPtr &base_interface_layers, const SupportGeneratorLayersPtr &base_layers, SupportGeneratorLayerStorage &layer_storage)
Definition SupportCommon.cpp:312
void export_print_z_polygons_and_extrusions_to_svg(const char *path, SupportGeneratorLayer **const layers, int n_layers, SupportLayer &support_layer)
Definition SupportDebug.cpp:77
void export_print_z_polygons_to_svg(const char *path, SupportGeneratorLayer **const layers, int n_layers)
Definition SupportDebug.cpp:59
std::pair< SupportGeneratorLayersPtr, SupportGeneratorLayersPtr > generate_interface_layers(const PrintObjectConfig &config, const SupportParameters &support_params, const SupportGeneratorLayersPtr &bottom_contacts, const SupportGeneratorLayersPtr &top_contacts, SupportGeneratorLayersPtr &top_interface_layers, SupportGeneratorLayersPtr &top_base_interface_layers, SupportGeneratorLayersPtr &intermediate_layers, SupportGeneratorLayerStorage &layer_storage)
Definition SupportCommon.cpp:124
Definition avrdude-slic3r.cpp:16
std::string debug_out_path(const char *name,...)
Definition utils.cpp:218
Slic3r::ExPolygons union_ex(const Slic3r::Polygons &subject, ClipperLib::PolyFillType fill_type)
Definition ClipperUtils.cpp:774
bool empty(const BoundingBoxBase< PointType, PointsType > &bb)
Definition BoundingBox.hpp:229

References bottom_contact_layers_and_layer_support_areas(), buildplate_covered(), Slic3r::debug_out_path(), Slic3r::empty(), EPSILON, Slic3r::SVG::export_expolygons(), Slic3r::FFFSupport::export_print_z_polygons_and_extrusions_to_svg(), Slic3r::FFFSupport::export_print_z_polygons_to_svg(), Slic3r::SlicingParameters::gap_object_support, Slic3r::SlicingParameters::gap_support_object, Slic3r::FFFSupport::SupportParameters::gap_xy, generate_base_layers(), Slic3r::FFFSupport::generate_interface_layers(), Slic3r::FFFSupport::generate_raft_base(), Slic3r::FFFSupport::generate_support_layers(), Slic3r::FFFSupport::generate_support_toolpaths(), m_object_config, m_slicing_params, m_support_params, raft_and_intermediate_support_layers(), top_contact_layers(), trim_support_layers_by_object(), trim_top_contacts_by_bottom_contacts(), and Slic3r::union_ex().

Referenced by Slic3r::PrintObject::_generate_support_material().

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

◆ generate_base_layers()

void Slic3r::PrintObjectSupportMaterial::generate_base_layers ( const PrintObject object,
const SupportGeneratorLayersPtr bottom_contacts,
const SupportGeneratorLayersPtr top_contacts,
SupportGeneratorLayersPtr intermediate_layers,
const std::vector< Polygons > &  layer_support_areas 
) const
private
2298{
2299#ifdef SLIC3R_DEBUG
2300 static int iRun = 0;
2301#endif /* SLIC3R_DEBUG */
2302
2303 if (top_contacts.empty())
2304 // No top contacts -> no intermediate layers will be produced.
2305 return;
2306
2307 BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::generate_base_layers() in parallel - start";
2308 tbb::parallel_for(
2309 tbb::blocked_range<size_t>(0, intermediate_layers.size()),
2310 [&object, &bottom_contacts, &top_contacts, &intermediate_layers, &layer_support_areas](const tbb::blocked_range<size_t>& range) {
2311 // index -2 means not initialized yet, -1 means intialized and decremented to 0 and then -1.
2312 int idx_top_contact_above = -2;
2313 int idx_bottom_contact_overlapping = -2;
2314 int idx_object_layer_above = -2;
2315 // Counting down due to the way idx_lower_or_equal caches indices to avoid repeated binary search over the complete sequence.
2316 for (int idx_intermediate = int(range.end()) - 1; idx_intermediate >= int(range.begin()); -- idx_intermediate)
2317 {
2318 BOOST_LOG_TRIVIAL(trace) << "Support generator - generate_base_layers - creating layer " <<
2319 idx_intermediate << " of " << intermediate_layers.size();
2320 SupportGeneratorLayer &layer_intermediate = *intermediate_layers[idx_intermediate];
2321 // Layers must be sorted by print_z.
2322 assert(idx_intermediate == 0 || layer_intermediate.print_z >= intermediate_layers[idx_intermediate - 1]->print_z);
2323
2324 // Find a top_contact layer touching the layer_intermediate from above, if any, and collect its polygons into polygons_new.
2325 // New polygons for layer_intermediate.
2326 Polygons polygons_new;
2327
2328 // Use the precomputed layer_support_areas. "idx_object_layer_above": above means above since the last iteration, not above after this call.
2329 idx_object_layer_above = idx_lower_or_equal(object.layers().begin(), object.layers().end(), idx_object_layer_above,
2330 [&layer_intermediate](const Layer* layer) { return layer->print_z <= layer_intermediate.print_z + EPSILON; });
2331
2332 // Polygons to trim polygons_new.
2333 Polygons polygons_trimming;
2334
2335 // Trimming the base layer with any overlapping top layer.
2336 // Following cases are recognized:
2337 // 1) top.bottom_z >= base.top_z -> No overlap, no trimming needed.
2338 // 2) base.bottom_z >= top.print_z -> No overlap, no trimming needed.
2339 // 3) base.print_z > top.print_z && base.bottom_z >= top.bottom_z -> Overlap, which will be solved inside generate_toolpaths() by reducing the base layer height where it overlaps the top layer. No trimming needed here.
2340 // 4) base.print_z > top.bottom_z && base.bottom_z < top.bottom_z -> Base overlaps with top.bottom_z. This must not happen.
2341 // 5) base.print_z <= top.print_z && base.bottom_z >= top.bottom_z -> Base is fully inside top. Trim base by top.
2342 idx_top_contact_above = idx_lower_or_equal(top_contacts, idx_top_contact_above,
2343 [&layer_intermediate](const SupportGeneratorLayer *layer){ return layer->bottom_z <= layer_intermediate.print_z - EPSILON; });
2344 // Collect all the top_contact layer intersecting with this layer.
2345 for (int idx_top_contact_overlapping = idx_top_contact_above; idx_top_contact_overlapping >= 0; -- idx_top_contact_overlapping) {
2346 SupportGeneratorLayer &layer_top_overlapping = *top_contacts[idx_top_contact_overlapping];
2347 if (layer_top_overlapping.print_z < layer_intermediate.bottom_z + EPSILON)
2348 break;
2349 // Base must not overlap with top.bottom_z.
2350 assert(! (layer_intermediate.print_z > layer_top_overlapping.bottom_z + EPSILON && layer_intermediate.bottom_z < layer_top_overlapping.bottom_z - EPSILON));
2351 if (layer_intermediate.print_z <= layer_top_overlapping.print_z + EPSILON && layer_intermediate.bottom_z >= layer_top_overlapping.bottom_z - EPSILON)
2352 // Base is fully inside top. Trim base by top.
2353 polygons_append(polygons_trimming, layer_top_overlapping.polygons);
2354 }
2355
2356 if (idx_object_layer_above < 0) {
2357 // layer_support_areas are synchronized with object layers and they contain projections of the contact layers above them.
2358 // This intermediate layer is not above any object layer, thus there is no information in layer_support_areas about
2359 // towers supporting contact layers intersecting the first object layer. Project these contact layers now.
2360 polygons_new = layer_support_areas.front();
2361 double first_layer_z = object.layers().front()->print_z;
2362 for (int i = idx_top_contact_above + 1; i < int(top_contacts.size()); ++ i) {
2363 SupportGeneratorLayer &contacts = *top_contacts[i];
2364 if (contacts.print_z > first_layer_z + EPSILON)
2365 break;
2366 assert(contacts.bottom_z > layer_intermediate.print_z - EPSILON);
2367 polygons_append(polygons_new, contacts.polygons);
2368 }
2369 } else
2370 polygons_new = layer_support_areas[idx_object_layer_above];
2371
2372 // Trimming the base layer with any overlapping bottom layer.
2373 // Following cases are recognized:
2374 // 1) bottom.bottom_z >= base.top_z -> No overlap, no trimming needed.
2375 // 2) base.bottom_z >= bottom.print_z -> No overlap, no trimming needed.
2376 // 3) base.print_z > bottom.bottom_z && base.bottom_z < bottom.bottom_z -> Overlap, which will be solved inside generate_toolpaths() by reducing the bottom layer height where it overlaps the base layer. No trimming needed here.
2377 // 4) base.print_z > bottom.print_z && base.bottom_z >= bottom.print_z -> Base overlaps with bottom.print_z. This must not happen.
2378 // 5) base.print_z <= bottom.print_z && base.bottom_z >= bottom.bottom_z -> Base is fully inside top. Trim base by top.
2379 idx_bottom_contact_overlapping = idx_lower_or_equal(bottom_contacts, idx_bottom_contact_overlapping,
2380 [&layer_intermediate](const SupportGeneratorLayer *layer){ return layer->bottom_print_z() <= layer_intermediate.print_z - EPSILON; });
2381 // Collect all the bottom_contacts layer intersecting with this layer.
2382 for (int i = idx_bottom_contact_overlapping; i >= 0; -- i) {
2383 SupportGeneratorLayer &layer_bottom_overlapping = *bottom_contacts[i];
2384 if (layer_bottom_overlapping.print_z < layer_intermediate.bottom_print_z() + EPSILON)
2385 break;
2386 // Base must not overlap with bottom.top_z.
2387 assert(! (layer_intermediate.print_z > layer_bottom_overlapping.print_z + EPSILON && layer_intermediate.bottom_z < layer_bottom_overlapping.print_z - EPSILON));
2388 if (layer_intermediate.print_z <= layer_bottom_overlapping.print_z + EPSILON && layer_intermediate.bottom_z >= layer_bottom_overlapping.bottom_print_z() - EPSILON)
2389 // Base is fully inside bottom. Trim base by bottom.
2390 polygons_append(polygons_trimming, layer_bottom_overlapping.polygons);
2391 }
2392
2393 #ifdef SLIC3R_DEBUG
2394 {
2395 BoundingBox bbox = get_extents(polygons_new);
2396 bbox.merge(get_extents(polygons_trimming));
2397 ::Slic3r::SVG svg(debug_out_path("support-intermediate-layers-raw-%d-%lf.svg", iRun, layer_intermediate.print_z), bbox);
2398 svg.draw(union_ex(polygons_new), "blue", 0.5f);
2399 svg.draw(to_polylines(polygons_new), "blue");
2400 svg.draw(union_safety_offset_ex(polygons_trimming), "red", 0.5f);
2401 svg.draw(to_polylines(polygons_trimming), "red");
2402 }
2403 #endif /* SLIC3R_DEBUG */
2404
2405 // Trim the polygons, store them.
2406 if (polygons_trimming.empty())
2407 layer_intermediate.polygons = std::move(polygons_new);
2408 else
2409 layer_intermediate.polygons = diff(
2410 polygons_new,
2411 polygons_trimming,
2412 ApplySafetyOffset::Yes); // safety offset to merge the touching source polygons
2413 layer_intermediate.layer_type = SupporLayerType::Base;
2414
2415 #if 0
2416 // coordf_t fillet_radius_scaled = scale_(m_object_config->support_material_spacing);
2417 // Fillet the base polygons and trim them again with the top, interface and contact layers.
2418 $base->{$i} = diff(
2419 offset2(
2420 $base->{$i},
2421 $fillet_radius_scaled,
2422 -$fillet_radius_scaled,
2423 # Use a geometric offsetting for filleting.
2424 JT_ROUND,
2425 0.2*$fillet_radius_scaled),
2426 $trim_polygons,
2427 false); // don't apply the safety offset.
2428 }
2429 #endif
2430 }
2431 });
2432 BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::generate_base_layers() in parallel - end";
2433
2434#ifdef SLIC3R_DEBUG
2435 for (SupportGeneratorLayersPtr::const_iterator it = intermediate_layers.begin(); it != intermediate_layers.end(); ++it)
2437 debug_out_path("support-intermediate-layers-untrimmed-%d-%lf.svg", iRun, (*it)->print_z),
2438 union_ex((*it)->polygons));
2439 ++ iRun;
2440#endif /* SLIC3R_DEBUG */
2441
2443}
auto range(Cont &&cont)
Definition libslic3r.h:356

References Slic3r::range().

Referenced by generate().

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

◆ has_contact_loops()

bool Slic3r::PrintObjectSupportMaterial::has_contact_loops ( ) const
inline
31{ return m_object_config->support_material_interface_contact_loops.value; }

References m_object_config.

◆ has_raft()

bool Slic3r::PrintObjectSupportMaterial::has_raft ( ) const
inline
25{ return m_slicing_params.has_raft(); }
bool has_raft() const
Definition Slicing.hpp:38

References Slic3r::SlicingParameters::has_raft(), and m_slicing_params.

+ Here is the call graph for this function:

◆ has_support()

bool Slic3r::PrintObjectSupportMaterial::has_support ( ) const
inline
27{ return m_object_config->support_material.value || m_object_config->support_material_enforce_layers; }

References m_object_config.

Referenced by build_plate_only().

+ Here is the caller graph for this function:

◆ raft_and_intermediate_support_layers()

SupportGeneratorLayersPtr Slic3r::PrintObjectSupportMaterial::raft_and_intermediate_support_layers ( const PrintObject object,
const SupportGeneratorLayersPtr bottom_contacts,
const SupportGeneratorLayersPtr top_contacts,
SupportGeneratorLayerStorage layer_storage 
) const
private
2107{
2108 SupportGeneratorLayersPtr intermediate_layers;
2109
2110 // Collect and sort the extremes (bottoms of the top contacts and tops of the bottom contacts).
2112 extremes.reserve(top_contacts.size() + bottom_contacts.size());
2113 for (size_t i = 0; i < top_contacts.size(); ++ i)
2114 // Bottoms of the top contact layers. In case of non-soluble supports,
2115 // the top contact layer thickness is not known yet.
2116 extremes.push_back(top_contacts[i]);
2117 for (size_t i = 0; i < bottom_contacts.size(); ++ i)
2118 // Tops of the bottom contact layers.
2119 extremes.push_back(bottom_contacts[i]);
2120 if (extremes.empty())
2121 return intermediate_layers;
2122
2123 auto layer_extreme_lower = [](const SupportGeneratorLayer *l1, const SupportGeneratorLayer *l2) {
2124 coordf_t z1 = l1->extreme_z();
2125 coordf_t z2 = l2->extreme_z();
2126 // If the layers are aligned, return the top contact surface first.
2127 return z1 < z2 || (z1 == z2 && l1->layer_type == SupporLayerType::TopContact && l2->layer_type == SupporLayerType::BottomContact);
2128 };
2129 std::sort(extremes.begin(), extremes.end(), layer_extreme_lower);
2130
2131 assert(extremes.empty() ||
2132 (extremes.front()->extreme_z() > m_slicing_params.raft_interface_top_z - EPSILON &&
2133 (m_slicing_params.raft_layers() == 1 || // only raft contact layer
2134 extremes.front()->layer_type == SupporLayerType::TopContact || // first extreme is a top contact layer
2135 extremes.front()->extreme_z() > m_slicing_params.first_print_layer_height - EPSILON)));
2136
2137 bool synchronize = this->synchronize_layers();
2138
2139#ifdef _DEBUG
2140 // Verify that the extremes are separated by m_support_layer_height_min.
2141 for (size_t i = 1; i < extremes.size(); ++ i) {
2142 assert(extremes[i]->extreme_z() - extremes[i-1]->extreme_z() == 0. ||
2143 extremes[i]->extreme_z() - extremes[i-1]->extreme_z() > m_support_params.support_layer_height_min - EPSILON);
2144 assert(extremes[i]->extreme_z() - extremes[i-1]->extreme_z() > 0. ||
2145 extremes[i]->layer_type == extremes[i-1]->layer_type ||
2146 (extremes[i]->layer_type == SupporLayerType::BottomContact && extremes[i - 1]->layer_type == SupporLayerType::TopContact));
2147 }
2148#endif
2149
2150 // Generate intermediate layers.
2151 // The first intermediate layer is the same as the 1st layer if there is no raft,
2152 // or the bottom of the first intermediate layer is aligned with the bottom of the raft contact layer.
2153 // Intermediate layers are always printed with a normal etrusion flow (non-bridging).
2154 size_t idx_layer_object = 0;
2155 size_t idx_extreme_first = 0;
2156 if (! extremes.empty() && std::abs(extremes.front()->extreme_z() - m_slicing_params.raft_interface_top_z) < EPSILON) {
2157 // This is a raft contact layer, its height has been decided in this->top_contact_layers().
2158 // Ignore this layer when calculating the intermediate support layers.
2159 assert(extremes.front()->layer_type == SupporLayerType::TopContact);
2160 ++ idx_extreme_first;
2161 }
2162 for (size_t idx_extreme = idx_extreme_first; idx_extreme < extremes.size(); ++ idx_extreme) {
2163 SupportGeneratorLayer *extr2 = extremes[idx_extreme];
2164 coordf_t extr2z = extr2->extreme_z();
2165 if (std::abs(extr2z - m_slicing_params.first_print_layer_height) < EPSILON) {
2166 // This is a bottom of a synchronized (or soluble) top contact layer, its height has been decided in this->top_contact_layers().
2167 assert(extr2->layer_type == SupporLayerType::TopContact);
2170 if (intermediate_layers.empty() || intermediate_layers.back()->print_z < m_slicing_params.first_print_layer_height) {
2171 SupportGeneratorLayer &layer_new = layer_storage.allocate_unguarded(SupporLayerType::Intermediate);
2172 layer_new.bottom_z = 0.;
2175 intermediate_layers.push_back(&layer_new);
2176 }
2177 continue;
2178 }
2179 assert(extr2z >= m_slicing_params.raft_interface_top_z + EPSILON);
2181 SupportGeneratorLayer *extr1 = (idx_extreme == idx_extreme_first) ? nullptr : extremes[idx_extreme - 1];
2182 // Fuse a support layer firmly to the raft top interface (not to the raft contacts).
2183 coordf_t extr1z = (extr1 == nullptr) ? m_slicing_params.raft_interface_top_z : extr1->extreme_z();
2184 assert(extr2z >= extr1z);
2185 assert(extr2z > extr1z || (extr1 != nullptr && extr2->layer_type == SupporLayerType::BottomContact));
2186 if (std::abs(extr1z) < EPSILON) {
2187 // This layer interval starts with the 1st layer. Print the 1st layer using the prescribed 1st layer thickness.
2188 // assert(! m_slicing_params.has_raft()); RaftingEdition: unclear where the issue is: assert fails with 1-layer raft & base supports
2189 assert(intermediate_layers.empty() || intermediate_layers.back()->print_z <= m_slicing_params.first_print_layer_height);
2190 // At this point only layers above first_print_layer_heigth + EPSILON are expected as the other cases were captured earlier.
2192 // Generate a new intermediate layer.
2193 SupportGeneratorLayer &layer_new = layer_storage.allocate_unguarded(SupporLayerType::Intermediate);
2194 layer_new.bottom_z = 0.;
2196 layer_new.height = extr1z;
2197 intermediate_layers.push_back(&layer_new);
2198 // Continue printing the other layers up to extr2z.
2199 }
2200 coordf_t dist = extr2z - extr1z;
2201 assert(dist >= 0.);
2202 if (dist == 0.)
2203 continue;
2204 // The new layers shall be at least m_support_layer_height_min thick.
2206 if (synchronize) {
2207 // Emit support layers synchronized with the object layers.
2208 // Find the first object layer, which has its print_z in this support Z range.
2209 while (idx_layer_object < object.layers().size() && object.layers()[idx_layer_object]->print_z < extr1z + EPSILON)
2210 ++ idx_layer_object;
2211 if (idx_layer_object == 0 && extr1z == m_slicing_params.raft_interface_top_z) {
2212 // Insert one base support layer below the object.
2213 SupportGeneratorLayer &layer_new = layer_storage.allocate_unguarded(SupporLayerType::Intermediate);
2216 layer_new.height = layer_new.print_z - layer_new.bottom_z;
2217 intermediate_layers.push_back(&layer_new);
2218 }
2219 // Emit all intermediate support layers synchronized with object layers up to extr2z.
2220 for (; idx_layer_object < object.layers().size() && object.layers()[idx_layer_object]->print_z < extr2z + EPSILON; ++ idx_layer_object) {
2221 SupportGeneratorLayer &layer_new = layer_storage.allocate_unguarded(SupporLayerType::Intermediate);
2222 layer_new.print_z = object.layers()[idx_layer_object]->print_z;
2223 layer_new.height = object.layers()[idx_layer_object]->height;
2224 layer_new.bottom_z = (idx_layer_object > 0) ? object.layers()[idx_layer_object - 1]->print_z : (layer_new.print_z - layer_new.height);
2225 assert(intermediate_layers.empty() || intermediate_layers.back()->print_z < layer_new.print_z + EPSILON);
2226 intermediate_layers.push_back(&layer_new);
2227 }
2228 } else {
2229 // Insert intermediate layers.
2230 size_t n_layers_extra = size_t(ceil(dist / m_slicing_params.max_suport_layer_height));
2231 assert(n_layers_extra > 0);
2232 coordf_t step = dist / coordf_t(n_layers_extra);
2233 if (extr1 != nullptr && extr1->layer_type == SupporLayerType::TopContact &&
2234 extr1->print_z + m_support_params.support_layer_height_min > extr1->bottom_z + step) {
2235 // The bottom extreme is a bottom of a top surface. Ensure that the gap
2236 // between the 1st intermediate layer print_z and extr1->print_z is not too small.
2238 // Generate the first intermediate layer.
2239 SupportGeneratorLayer &layer_new = layer_storage.allocate_unguarded(SupporLayerType::Intermediate);
2240 layer_new.bottom_z = extr1->bottom_z;
2241 layer_new.print_z = extr1z = extr1->print_z;
2242 layer_new.height = extr1->height;
2243 intermediate_layers.push_back(&layer_new);
2244 dist = extr2z - extr1z;
2245 n_layers_extra = size_t(ceil(dist / m_slicing_params.max_suport_layer_height));
2246 if (n_layers_extra == 0)
2247 continue;
2248 // Continue printing the other layers up to extr2z.
2249 step = dist / coordf_t(n_layers_extra);
2250 }
2251 if (! m_slicing_params.soluble_interface && extr2->layer_type == SupporLayerType::TopContact) {
2252 // This is a top interface layer, which does not have a height assigned yet. Do it now.
2253 assert(extr2->height == 0.);
2255 extr2->height = step;
2256 extr2->bottom_z = extr2z = extr2->print_z - step;
2257 if (-- n_layers_extra == 0)
2258 continue;
2259 }
2260 coordf_t extr2z_large_steps = extr2z;
2261 // Take the largest allowed step in the Z axis until extr2z_large_steps is reached.
2262 for (size_t i = 0; i < n_layers_extra; ++ i) {
2263 SupportGeneratorLayer &layer_new = layer_storage.allocate_unguarded(SupporLayerType::Intermediate);
2264 if (i + 1 == n_layers_extra) {
2265 // Last intermediate layer added. Align the last entered layer with extr2z_large_steps exactly.
2266 layer_new.bottom_z = (i == 0) ? extr1z : intermediate_layers.back()->print_z;
2267 layer_new.print_z = extr2z_large_steps;
2268 layer_new.height = layer_new.print_z - layer_new.bottom_z;
2269 }
2270 else {
2271 // Intermediate layer, not the last added.
2272 layer_new.height = step;
2273 layer_new.bottom_z = extr1z + i * step;
2274 layer_new.print_z = layer_new.bottom_z + step;
2275 }
2276 assert(intermediate_layers.empty() || intermediate_layers.back()->print_z <= layer_new.print_z);
2277 intermediate_layers.push_back(&layer_new);
2278 }
2279 }
2280 }
2281
2282#ifdef _DEBUG
2283 for (size_t i = 0; i < top_contacts.size(); ++i)
2284 assert(top_contacts[i]->height > 0.);
2285#endif /* _DEBUG */
2286
2287 return intermediate_layers;
2288}
EIGEN_DEVICE_FUNC const CeilReturnType ceil() const
Definition ArrayCwiseUnaryOps.h:402
coordf_t height
Definition SupportLayer.hpp:96
SupporLayerType layer_type
Definition SupportLayer.hpp:89
coordf_t bottom_z
Definition SupportLayer.hpp:94
coordf_t print_z
Definition SupportLayer.hpp:91
coordf_t extreme_z() const
Definition SupportLayer.hpp:87
SupportGeneratorLayer & allocate_unguarded(SupporLayerType layer_type)
Definition SupportLayer.hpp:120
bool synchronize_layers() const
Definition SupportMaterial.hpp:30
T dist(const boost::polygon::point_data< T > &p1, const boost::polygon::point_data< T > &p2)
Definition Geometry.cpp:280
T l2(const boost::geometry::model::d2::point_xy< T > &v)
Definition ExtrusionSimulator.cpp:166
double coordf_t
Definition GUI_ObjectList.hpp:36
TPoint< P > back(const P &p)
Definition geometry_traits.hpp:873
Coord step(const Coord &crd, Dir d)
Definition MarchingSquares.hpp:137
coordf_t support_layer_height_min
Definition SupportParameters.hpp:55
coordf_t object_print_z_min
Definition Slicing.hpp:97
coordf_t first_print_layer_height
Definition Slicing.hpp:70
coordf_t raft_interface_top_z
Definition Slicing.hpp:94
bool soluble_interface
Definition Slicing.hpp:82
size_t raft_layers() const
Definition Slicing.hpp:39
coordf_t max_suport_layer_height
Definition Slicing.hpp:66

References Slic3r::FFFSupport::SupportGeneratorLayerStorage::allocate_unguarded(), Slic3r::FFFSupport::SupportGeneratorLayer::bottom_z, ceil(), EPSILON, Slic3r::FFFSupport::SupportGeneratorLayer::extreme_z(), Slic3r::FFFSupport::SupportGeneratorLayer::height, Slic3r::l2(), Slic3r::FFFSupport::SupportGeneratorLayer::layer_type, and Slic3r::FFFSupport::SupportGeneratorLayer::print_z.

Referenced by generate().

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

◆ synchronize_layers()

bool Slic3r::PrintObjectSupportMaterial::synchronize_layers ( ) const
inline
30{ return m_slicing_params.soluble_interface && m_object_config->support_material_synchronize_layers.value; }

References m_object_config, m_slicing_params, and Slic3r::SlicingParameters::soluble_interface.

◆ top_contact_layers()

SupportGeneratorLayersPtr Slic3r::PrintObjectSupportMaterial::top_contact_layers ( const PrintObject object,
const std::vector< Polygons > &  buildplate_covered,
SupportGeneratorLayerStorage layer_storage 
) const
private
1645{
1646#ifdef SLIC3R_DEBUG
1647 static int iRun = 0;
1648 ++ iRun;
1649 #define SLIC3R_IRUN , iRun
1650#endif /* SLIC3R_DEBUG */
1651
1652 // Slice support enforcers / support blockers.
1653 SupportAnnotations annotations(object, buildplate_covered);
1654
1655 // Output layers, sorted by top Z.
1656 SupportGeneratorLayersPtr contact_out;
1657
1658 BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::top_contact_layers() in parallel - start";
1659 // Determine top contact areas.
1660 // If generating raft only (no support), only calculate top contact areas for the 0th layer.
1661 // If having a raft, start with 0th layer, otherwise with 1st layer.
1662 // Note that layer_id < layer->id when raft_layers > 0 as the layer->id incorporates the raft layers.
1663 // So layer_id == 0 means first object layer and layer->id == 0 means first print layer if there are no explicit raft layers.
1664 size_t num_layers = this->has_support() ? object.layer_count() : 1;
1665 // For each overhang layer, two supporting layers may be generated: One for the overhangs extruded with a bridging flow,
1666 // and the other for the overhangs extruded with a normal flow.
1667 contact_out.assign(num_layers * 2, nullptr);
1668 tbb::parallel_for(tbb::blocked_range<size_t>(this->has_raft() ? 0 : 1, num_layers),
1669 [this, &object, &annotations, &layer_storage, &contact_out]
1670 (const tbb::blocked_range<size_t>& range) {
1671 for (size_t layer_id = range.begin(); layer_id < range.end(); ++ layer_id)
1672 {
1673 const Layer &layer = *object.layers()[layer_id];
1674 Polygons lower_layer_polygons = (layer_id == 0) ? Polygons() : to_polygons(object.layers()[layer_id - 1]->lslices);
1675 SlicesMarginCache slices_margin;
1676
1677 auto [overhang_polygons, contact_polygons, enforcer_polygons, no_interface_offset] =
1678 detect_overhangs(layer, layer_id, lower_layer_polygons, *m_print_config, *m_object_config, annotations, slices_margin, m_support_params.gap_xy
1679 #ifdef SLIC3R_DEBUG
1680 , iRun
1681 #endif // SLIC3R_DEBUG
1682 );
1683
1684 // Now apply the contact areas to the layer where they need to be made.
1685 if (! contact_polygons.empty() || ! overhang_polygons.empty()) {
1686 // Allocate the two empty layers.
1687 auto [new_layer, bridging_layer] = new_contact_layer(*m_print_config, *m_object_config, m_slicing_params, m_support_params.support_layer_height_min, layer, layer_storage);
1688 if (new_layer) {
1689 // Fill the non-bridging layer with polygons.
1690 fill_contact_layer(*new_layer, layer_id, m_slicing_params,
1691 *m_object_config, slices_margin, overhang_polygons, contact_polygons, enforcer_polygons, lower_layer_polygons,
1692 m_support_params.support_material_flow, no_interface_offset
1693 #ifdef SLIC3R_DEBUG
1694 , iRun, layer
1695 #endif // SLIC3R_DEBUG
1696 );
1697 // Insert new layer even if there is no interface generated: Likely the support angle is not steep enough to require dense interface,
1698 // however generating a sparse support will be useful for the object stability.
1699 // if (! new_layer->polygons.empty())
1700 contact_out[layer_id * 2] = new_layer;
1701 if (bridging_layer != nullptr) {
1702 bridging_layer->polygons = new_layer->polygons;
1703 bridging_layer->contact_polygons = std::make_unique<Polygons>(*new_layer->contact_polygons);
1704 bridging_layer->overhang_polygons = std::make_unique<Polygons>(*new_layer->overhang_polygons);
1705 if (new_layer->enforcer_polygons)
1706 bridging_layer->enforcer_polygons = std::make_unique<Polygons>(*new_layer->enforcer_polygons);
1707 contact_out[layer_id * 2 + 1] = bridging_layer;
1708 }
1709 }
1710 }
1711 }
1712 });
1713
1714 // Compress contact_out, remove the nullptr items.
1715 remove_nulls(contact_out);
1716
1717 // Merge close contact layers conservatively: If two layers are closer than the minimum allowed print layer height (the min_layer_height parameter),
1718 // the top contact layer is merged into the bottom contact layer.
1719 merge_contact_layers(m_slicing_params, m_support_params.support_layer_height_min, contact_out);
1720
1721 BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::top_contact_layers() in parallel - end";
1722
1723 return contact_out;
1724}
bool has_raft() const
Definition SupportMaterial.hpp:25
#define const
Definition getopt.c:38
static std::tuple< Polygons, Polygons, Polygons, float > detect_overhangs(const Layer &layer, const size_t layer_id, const Polygons &lower_layer_polygons, const PrintConfig &print_config, const PrintObjectConfig &object_config, SupportAnnotations &annotations, SlicesMarginCache &slices_margin, const double gap_xy)
Definition SupportMaterial.cpp:1117
static void merge_contact_layers(const SlicingParameters &slicing_params, double support_layer_height_min, SupportGeneratorLayersPtr &layers)
Definition SupportMaterial.cpp:1597
static void fill_contact_layer(SupportGeneratorLayer &new_layer, size_t layer_id, const SlicingParameters &slicing_params, const PrintObjectConfig &object_config, const SlicesMarginCache &slices_margin, const Polygons &overhang_polygons, const Polygons &contact_polygons, const Polygons &enforcer_polygons, const Polygons &lower_layer_polygons, const Flow &support_material_flow, float no_interface_offset)
Definition SupportMaterial.cpp:1444
Polygons to_polygons(const ExPolygon &src)
Definition ExPolygon.hpp:281
void remove_nulls(std::vector< T * > &vec)
Definition libslic3r.h:180
static std::pair< SupportGeneratorLayer *, SupportGeneratorLayer * > new_contact_layer(const PrintConfig &print_config, const PrintObjectConfig &object_config, const SlicingParameters &slicing_params, const coordf_t support_layer_height_min, const Layer &layer, SupportGeneratorLayerStorage &layer_storage)
Definition SupportMaterial.cpp:1354

References Slic3r::detect_overhangs(), Slic3r::fill_contact_layer(), Slic3r::merge_contact_layers(), Slic3r::new_contact_layer(), Slic3r::range(), Slic3r::remove_nulls(), and Slic3r::to_polygons().

Referenced by generate().

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

◆ trim_support_layers_by_object()

void Slic3r::PrintObjectSupportMaterial::trim_support_layers_by_object ( const PrintObject object,
SupportGeneratorLayersPtr support_layers,
const coordf_t  gap_extra_above,
const coordf_t  gap_extra_below,
const coordf_t  gap_xy 
) const
private
2451{
2452 const float gap_xy_scaled = float(scale_(gap_xy));
2453
2454 // Collect non-empty layers to be processed in parallel.
2455 // This is a good idea as pulling a thread from a thread pool for an empty task is expensive.
2456 SupportGeneratorLayersPtr nonempty_layers;
2457 nonempty_layers.reserve(support_layers.size());
2458 for (size_t idx_layer = 0; idx_layer < support_layers.size(); ++ idx_layer) {
2459 SupportGeneratorLayer *support_layer = support_layers[idx_layer];
2460 if (! support_layer->polygons.empty() && support_layer->print_z >= m_slicing_params.raft_contact_top_z + EPSILON)
2461 // Non-empty support layer and not a raft layer.
2462 nonempty_layers.push_back(support_layer);
2463 }
2464
2465 // For all intermediate support layers:
2466 BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::trim_support_layers_by_object() in parallel - start";
2467 tbb::parallel_for(
2468 tbb::blocked_range<size_t>(0, nonempty_layers.size()),
2469 [this, &object, &nonempty_layers, gap_extra_above, gap_extra_below, gap_xy_scaled](const tbb::blocked_range<size_t>& range) {
2470 size_t idx_object_layer_overlapping = size_t(-1);
2471 for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) {
2472 SupportGeneratorLayer &support_layer = *nonempty_layers[idx_layer];
2473 // BOOST_LOG_TRIVIAL(trace) << "Support generator - trim_support_layers_by_object - trimmming non-empty layer " << idx_layer << " of " << nonempty_layers.size();
2474 assert(! support_layer.polygons.empty() && support_layer.print_z >= m_slicing_params.raft_contact_top_z + EPSILON);
2475 // Find the overlapping object layers including the extra above / below gap.
2476 coordf_t z_threshold = support_layer.bottom_print_z() - gap_extra_below + EPSILON;
2477 idx_object_layer_overlapping = idx_higher_or_equal(
2478 object.layers().begin(), object.layers().end(), idx_object_layer_overlapping,
2479 [z_threshold](const Layer *layer){ return layer->print_z >= z_threshold; });
2480 // Collect all the object layers intersecting with this layer.
2481 Polygons polygons_trimming;
2482 size_t i = idx_object_layer_overlapping;
2483 for (; i < object.layers().size(); ++ i) {
2484 const Layer &object_layer = *object.layers()[i];
2485 if (object_layer.bottom_z() > support_layer.print_z + gap_extra_above - EPSILON)
2486 break;
2487 polygons_append(polygons_trimming, offset(object_layer.lslices, gap_xy_scaled, SUPPORT_SURFACES_OFFSET_PARAMETERS));
2488 }
2489 if (! m_slicing_params.soluble_interface && m_object_config->thick_bridges) {
2490 // Collect all bottom surfaces, which will be extruded with a bridging flow.
2491 for (; i < object.layers().size(); ++ i) {
2492 const Layer &object_layer = *object.layers()[i];
2493 bool some_region_overlaps = false;
2494 for (LayerRegion *region : object_layer.regions()) {
2495 coordf_t bridging_height = region->region().bridging_height_avg(*m_print_config);
2496 if (object_layer.print_z - bridging_height > support_layer.print_z + gap_extra_above - EPSILON)
2497 break;
2498 some_region_overlaps = true;
2499 polygons_append(polygons_trimming,
2500 offset(region->fill_surfaces().filter_by_type(stBottomBridge), gap_xy_scaled, SUPPORT_SURFACES_OFFSET_PARAMETERS));
2501 if (region->region().config().overhangs.value)
2502 // Add bridging perimeters.
2503 SupportMaterialInternal::collect_bridging_perimeter_areas(region->perimeters(), gap_xy_scaled, polygons_trimming);
2504 }
2505 if (! some_region_overlaps)
2506 break;
2507 }
2508 }
2509 // $layer->slices contains the full shape of layer, thus including
2510 // perimeter's width. $support contains the full shape of support
2511 // material, thus including the width of its foremost extrusion.
2512 // We leave a gap equal to a full extrusion width.
2513 support_layer.polygons = diff(support_layer.polygons, polygons_trimming);
2514 }
2515 });
2516 BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::trim_support_layers_by_object() in parallel - end";
2517}
Polygons polygons
Definition SupportLayer.hpp:107
coordf_t raft_contact_top_z
Definition Slicing.hpp:95

References EPSILON, Slic3r::FFFSupport::SupportGeneratorLayer::polygons, Slic3r::FFFSupport::SupportGeneratorLayer::print_z, Slic3r::range(), and scale_.

Referenced by generate().

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

◆ trim_top_contacts_by_bottom_contacts()

void Slic3r::PrintObjectSupportMaterial::trim_top_contacts_by_bottom_contacts ( const PrintObject object,
const SupportGeneratorLayersPtr bottom_contacts,
SupportGeneratorLayersPtr top_contacts 
) const
private
2079{
2080 tbb::parallel_for(tbb::blocked_range<int>(0, int(top_contacts.size())),
2081 [&bottom_contacts, &top_contacts](const tbb::blocked_range<int>& range) {
2082 int idx_bottom_overlapping_first = -2;
2083 // For all top contact layers, counting downwards due to the way idx_higher_or_equal caches the last index to avoid repeated binary search.
2084 for (int idx_top = range.end() - 1; idx_top >= range.begin(); -- idx_top) {
2085 SupportGeneratorLayer &layer_top = *top_contacts[idx_top];
2086 // Find the first bottom layer overlapping with layer_top.
2087 idx_bottom_overlapping_first = idx_lower_or_equal(bottom_contacts, idx_bottom_overlapping_first, [&layer_top](const SupportGeneratorLayer *layer_bottom){ return layer_bottom->bottom_print_z() - EPSILON <= layer_top.bottom_z; });
2088 // For all top contact layers overlapping with the thick bottom contact layer:
2089 for (int idx_bottom_overlapping = idx_bottom_overlapping_first; idx_bottom_overlapping >= 0; -- idx_bottom_overlapping) {
2090 const SupportGeneratorLayer &layer_bottom = *bottom_contacts[idx_bottom_overlapping];
2091 assert(layer_bottom.bottom_print_z() - EPSILON <= layer_top.bottom_z);
2092 if (layer_top.print_z < layer_bottom.print_z + EPSILON) {
2093 // Layers overlap. Trim layer_top with layer_bottom.
2094 layer_top.polygons = diff(layer_top.polygons, layer_bottom.polygons);
2095 } else
2096 break;
2097 }
2098 }
2099 });
2100}

References Slic3r::range().

Referenced by generate().

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

Member Data Documentation

◆ m_object_config

const PrintObjectConfig* Slic3r::PrintObjectSupportMaterial::m_object_config
private

◆ m_print_config

const PrintConfig* Slic3r::PrintObjectSupportMaterial::m_print_config
private

◆ m_slicing_params

SlicingParameters Slic3r::PrintObjectSupportMaterial::m_slicing_params
private

◆ m_support_params

SupportParameters Slic3r::PrintObjectSupportMaterial::m_support_params
private

Referenced by generate().


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