OrcaSlicer latest
OrcaSlicer
Loading...
Searching...
No Matches
Slic3r::PrintObjectSupportMaterial Class Reference

#include </home/runner/work/OrcaSlicer/OrcaSlicer/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 Member Functions

std::vector< Polygons > buildplate_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 PrintObjectConfig * m_object_config
SlicingParameters m_slicing_params
SupportParameters m_support_params

Detailed Description

Constructor & Destructor Documentation

◆ PrintObjectSupportMaterial()

Slic3r::PrintObjectSupportMaterial::PrintObjectSupportMaterial ( const PrintObject * object,
const SlicingParameters & slicing_params )
364 :
365 m_print_config (&object->print()->config()),
366 m_object_config (&object->config()),
367 m_slicing_params (slicing_params),
368 m_support_params (*object)
369{
370}
const PrintConfig * m_print_config
Definition SupportMaterial.hpp:91
SlicingParameters m_slicing_params
Definition SupportMaterial.hpp:95
const PrintObjectConfig * m_object_config
Definition SupportMaterial.hpp:92
SupportParameters m_support_params
Definition SupportMaterial.hpp:97

References m_object_config, m_print_config, m_slicing_params, and m_support_params.

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
2762{
2763 if (top_contacts.empty())
2765
2766#ifdef SLIC3R_DEBUG
2767 static size_t s_iRun = 0;
2768 size_t iRun = s_iRun ++;
2769#endif /* SLIC3R_DEBUG */
2770
2771 //FIXME higher expansion_to_slice here? why?
2772 //const auto expansion_to_slice = m_support_material_flow.scaled_spacing() / 2 + 25;
2773 const SupportGridParams grid_params(*m_object_config, m_support_params.support_material_flow);
2774 const bool buildplate_only = ! buildplate_covered.empty();
2775 const bool has_belt_floor = std::abs(m_slicing_params.belt_floor_shear_factor) > EPSILON;
2776
2777 // Allocate empty surface areas, one per object layer.
2778 layer_support_areas.assign(object.total_layer_count(), Polygons());
2779
2780 // find object top surfaces
2781 // we'll use them to clip our support and detect where does it stick
2782 SupportGeneratorLayersPtr bottom_contacts;
2783
2784 // There is some support to be built, if there are non-empty top surfaces detected.
2785 // Sum of unsupported contact areas above the current layer.print_z.
2786 Polygons overhangs_projection;
2787 // Sum of unsupported enforcer contact areas above the current layer.print_z.
2788 // Only used if "supports on build plate only" is enabled and both automatic and support enforcers are enabled.
2789 Polygons enforcers_projection;
2790 // Last top contact layer visited when collecting the projection of contact areas.
2791 int contact_idx = int(top_contacts.size()) - 1;
2792 for (int layer_id = int(object.total_layer_count()) - 2; layer_id >= 0; -- layer_id) {
2793 BOOST_LOG_TRIVIAL(trace) << "Support generator - bottom_contact_layers - layer " << layer_id;
2794 const Layer &layer = *object.get_layer(layer_id);
2795 // Collect projections of all contact areas above or at the same level as this top surface.
2796#ifdef SLIC3R_DEBUG
2797 Polygons polygons_new;
2798 Polygons enforcers_new;
2799#endif // SLIC3R_DEBUG
2800 for (; contact_idx >= 0 && top_contacts[contact_idx]->print_z > layer.print_z - EPSILON; -- contact_idx) {
2801 SupportGeneratorLayer &top_contact = *top_contacts[contact_idx];
2802#ifndef SLIC3R_DEBUG
2803 Polygons polygons_new;
2804 Polygons enforcers_new;
2805#endif // SLIC3R_DEBUG
2806 // Contact surfaces are expanded away from the object, trimmed by the object.
2807 // Use a slight positive offset to overlap the touching regions.
2808#if 0
2809 // Merge and collect the contact polygons. The contact polygons are inflated, but not extended into a grid form.
2810 polygons_append(polygons_new, offset(*top_contact.contact_polygons, SCALED_EPSILON));
2811 if (top_contact.enforcer_polygons)
2812 polygons_append(enforcers_new, offset(*top_contact.enforcer_polygons, SCALED_EPSILON));
2813#else
2814 // Consume the contact_polygons. The contact polygons are already expanded into a grid form, and they are a tiny bit smaller
2815 // than the grid cells.
2816 polygons_append(polygons_new, std::move(*top_contact.contact_polygons));
2817 if (top_contact.enforcer_polygons)
2818 polygons_append(enforcers_new, std::move(*top_contact.enforcer_polygons));
2819#endif
2820 // These are the overhang surfaces. They are touching the object and they are not expanded away from the object.
2821 // Use a slight positive offset to overlap the touching regions.
2822 polygons_append(polygons_new, expand(*top_contact.overhang_polygons, float(SCALED_EPSILON)));
2823 polygons_append(overhangs_projection, union_(polygons_new));
2824 polygons_append(enforcers_projection, enforcers_new);
2825 }
2826 if (overhangs_projection.empty() && enforcers_projection.empty())
2827 continue;
2828
2829 // Overhangs_projection will be filled in asynchronously, move it away.
2830 Polygons overhangs_projection_raw = union_(std::move(overhangs_projection));
2831 Polygons enforcers_projection_raw = union_(std::move(enforcers_projection));
2832
2833 tbb::task_group task_group;
2834 const Polygons &overhangs_for_bottom_contacts = buildplate_only ? enforcers_projection_raw : overhangs_projection_raw;
2835 if (! overhangs_for_bottom_contacts.empty())
2836 // Find the bottom contact layers above the top surfaces of this layer,
2837 // and also detect belt floor contacts if belt mode is active.
2838 task_group.run([this, &object, &layer, &top_contacts, contact_idx, &layer_storage, &layer_support_areas, &bottom_contacts, &overhangs_for_bottom_contacts, has_belt_floor
2839 #ifdef SLIC3R_DEBUG
2840 , iRun, &polygons_new
2841 #endif // SLIC3R_DEBUG
2842 ] {
2843 // Find the bottom contact layers above the top surfaces of this layer.
2844 SupportGeneratorLayer *layer_new = detect_bottom_contacts(
2845 m_slicing_params, m_support_params, object, layer, top_contacts, contact_idx, layer_storage, layer_support_areas, overhangs_for_bottom_contacts
2846#ifdef SLIC3R_DEBUG
2847 , iRun, polygons_new
2848#endif // SLIC3R_DEBUG
2849 );
2850 if (layer_new)
2851 bottom_contacts.push_back(layer_new);
2852 // Belt floor phantom surface: detect where support meets the belt plane.
2853 if (has_belt_floor) {
2854 SupportGeneratorLayer *belt_layer = detect_belt_floor_bottom_contacts(
2856 layer, top_contacts, contact_idx, layer_storage,
2857 layer_support_areas, overhangs_for_bottom_contacts);
2858 if (belt_layer)
2859 bottom_contacts.push_back(belt_layer);
2860 }
2861 });
2862
2863 Polygons &layer_support_area = layer_support_areas[layer_id];
2864 Polygons *layer_buildplate_covered = buildplate_covered.empty() ? nullptr : &buildplate_covered[layer_id];
2865 // Filtering the propagated support columns to two extrusions, overlapping by maximum 20%.
2866// 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()));
2867 task_group.run([&grid_params, &overhangs_projection, &overhangs_projection_raw, &layer, &layer_support_area, layer_buildplate_covered /* , column_propagation_filtering_radius */
2868#ifdef SLIC3R_DEBUG
2869 , iRun, layer_id
2870#endif /* SLIC3R_DEBUG */
2871 ] {
2872 // buildplate_covered[layer_id] will be consumed here.
2873 std::tie(layer_support_area, overhangs_projection) = project_support_to_grid(layer, grid_params, overhangs_projection_raw, layer_buildplate_covered
2874#ifdef SLIC3R_DEBUG
2875 , iRun, layer_id, "general"
2876#endif /* SLIC3R_DEBUG */
2877 );
2878 // When propagating support areas downwards, stop propagating the support column if it becomes too thin to be printable.
2879 //overhangs_projection = opening(overhangs_projection, column_propagation_filtering_radius);
2880 });
2881
2882 Polygons layer_support_area_enforcers;
2883 if (! enforcers_projection.empty())
2884 // Project the enforcers polygons downwards, don't trim them with the "buildplate only" polygons.
2885 task_group.run([&grid_params, &enforcers_projection, &enforcers_projection_raw, &layer, &layer_support_area_enforcers
2886#ifdef SLIC3R_DEBUG
2887 , iRun, layer_id
2888#endif /* SLIC3R_DEBUG */
2889 ]{
2890 std::tie(layer_support_area_enforcers, enforcers_projection) = project_support_to_grid(layer, grid_params, enforcers_projection_raw, nullptr
2891#ifdef SLIC3R_DEBUG
2892 , iRun, layer_id, "enforcers"
2893#endif /* SLIC3R_DEBUG */
2894 );
2895 });
2896
2897 task_group.wait();
2898
2899 // Belt floor: clip projections and support areas so support doesn't
2900 // propagate below the belt plane.
2901 if (has_belt_floor) {
2903 m_slicing_params, *m_print_config, object, layer.print_z);
2904 if (! valid_region.empty()) {
2905 if (! overhangs_projection.empty())
2906 overhangs_projection = intersection(overhangs_projection, valid_region);
2907 if (! enforcers_projection.empty())
2908 enforcers_projection = intersection(enforcers_projection, valid_region);
2909 if (! layer_support_area.empty())
2910 layer_support_area = intersection(layer_support_area, valid_region);
2911 if (! layer_support_area_enforcers.empty())
2912 layer_support_area_enforcers = intersection(layer_support_area_enforcers, valid_region);
2913 }
2914 }
2915
2916 if (! layer_support_area_enforcers.empty()) {
2917 if (layer_support_area.empty())
2918 layer_support_area = std::move(layer_support_area_enforcers);
2919 else
2920 layer_support_area = union_(layer_support_area, layer_support_area_enforcers);
2921 }
2922 } // over all layers downwards
2923
2924 std::reverse(bottom_contacts.begin(), bottom_contacts.end());
2925 trim_support_layers_by_object(object, bottom_contacts, m_slicing_params.gap_support_object, m_slicing_params.gap_object_support, m_support_params.gap_xy);
2927 return bottom_contacts;
2928}
#define EPSILON
Definition ColorUtils.cpp:64
std::vector< Polygons > buildplate_covered(const PrintObject &object) const
Definition SupportMaterial.cpp:1377
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:3327
#define SCALED_EPSILON
Definition libslic3r.h:109
Slic3r::Polygons union_(const Slic3r::Polygons &subject)
Definition ClipperUtils.cpp:801
void trace(unsigned int level, const char *message)
Definition utils.cpp:247
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:2678
Slic3r::Polygons expand(const Slic3r::Polygon &polygon, const float delta, JoinType joinType=DefaultJoinType, double miterLimit=DefaultMiterLimit)
Definition ClipperUtils.hpp:397
Slic3r::Polygons intersection(const Slic3r::Polygon &subject, const Slic3r::Polygon &clip, ApplySafetyOffset do_safety_offset)
Definition ClipperUtils.cpp:769
std::vector< SupportGeneratorLayer * > SupportGeneratorLayersPtr
Definition SupportLayer.hpp:146
std::vector< Polygon, PointsAllocator< Polygon > > Polygons
Definition Polygon.hpp:22
Slic3r::Polygons offset(const Slic3r::Polygon &polygon, const float delta, JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:582
static SupportGeneratorLayer * detect_belt_floor_bottom_contacts(const SlicingParameters &slicing_params, const SupportParameters &support_params, const PrintConfig &print_config, 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:2602
static void trim_support_layers_by_belt_floor(const SlicingParameters &slicing_params, const PrintConfig &print_config, const PrintObject &object, SupportGeneratorLayersPtr &support_layers)
Definition SupportMaterial.cpp:3308
static Polygons belt_floor_valid_region_polygon(const SlicingParameters &slicing_params, const PrintConfig &print_config, const PrintObject &object, coordf_t print_z)
Definition SupportMaterial.cpp:672
void polygons_append(Polygons &dst, const ExPolygon &src)
Definition ExPolygon.hpp:411
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:2463

References Slic3r::belt_floor_valid_region_polygon(), bottom_contact_layers_and_layer_support_areas(), buildplate_covered(), Slic3r::SupportGeneratorLayer::contact_polygons, Slic3r::detect_belt_floor_bottom_contacts(), Slic3r::detect_bottom_contacts(), Slic3r::SupportGeneratorLayer::enforcer_polygons, EPSILON, Slic3r::expand(), Slic3r::intersection(), m_object_config, m_print_config, m_slicing_params, m_support_params, Slic3r::offset(), Slic3r::SupportGeneratorLayer::overhang_polygons, Slic3r::polygons_append(), Slic3r::Layer::print_z, Slic3r::project_support_to_grid(), SCALED_EPSILON, Slic3r::trace(), Slic3r::trim_support_layers_by_belt_floor(), trim_support_layers_by_object(), and Slic3r::union_().

Referenced by bottom_contact_layers_and_layer_support_areas(), and 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
31{ return this->has_support() && m_object_config->support_on_build_plate_only.value; }
bool has_support() const
Definition SupportMaterial.hpp:30

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
1378{
1379 // Build support on a build plate only? If so, then collect and union all the surfaces below the current layer.
1380 // Unfortunately this is an inherently serial process.
1381 const bool buildplate_only = this->build_plate_only();
1382 std::vector<Polygons> buildplate_covered;
1383 if (buildplate_only) {
1384 BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::buildplate_covered() - start";
1385 buildplate_covered.assign(object.layers().size(), Polygons());
1386 //FIXME prefix sum algorithm, parallelize it! Parallelization will also likely be more numerically stable.
1387 for (size_t layer_id = 1; layer_id < object.layers().size(); ++ layer_id) {
1388 const Layer &lower_layer = *object.layers()[layer_id-1];
1389 // Merge the new slices with the preceding slices.
1390 // Apply the safety offset to the newly added polygons, so they will connect
1391 // with the polygons collected before,
1392 // but don't apply the safety offset during the union operation as it would
1393 // inflate the polygons over and over.
1394 Polygons &covered = buildplate_covered[layer_id];
1395 covered = buildplate_covered[layer_id - 1];
1396 polygons_append(covered, offset(lower_layer.lslices, scale_(0.01)));
1397 covered = union_(covered);
1398 }
1399 BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::buildplate_covered() - end";
1400 }
1401 return buildplate_covered;
1402}
bool build_plate_only() const
Definition SupportMaterial.hpp:31
#define scale_(val)
Definition libslic3r.h:106

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

Referenced by bottom_contact_layers_and_layer_support_areas(), buildplate_covered(), generate(), and top_contact_layers().

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

◆ generate()

void Slic3r::PrintObjectSupportMaterial::generate ( PrintObject & object)
417{
418 BOOST_LOG_TRIVIAL(info) << "Support generator - Start";
419
420 coordf_t max_object_layer_height = 0.;
421 for (size_t i = 0; i < object.layer_count(); ++ i)
422 max_object_layer_height = std::max(max_object_layer_height, object.layers()[i]->height);
423
424 // Layer instances will be allocated by std::deque and they will be kept until the end of this function call.
425 // The layers will be referenced by various LayersPtr (of type std::vector<Layer*>)
426 SupportGeneratorLayerStorage layer_storage;
427
428 BOOST_LOG_TRIVIAL(info) << "Support generator - Creating top contacts";
429
430 // Per object layer projection of the object below the layer into print bed.
431 std::vector<Polygons> buildplate_covered = this->buildplate_covered(object);
432
433 // Determine the top contact surfaces of the support, defined as:
434 // contact = overhangs - clearance + margin
435 // This method is responsible for identifying what contact surfaces
436 // should the support material expose to the object in order to guarantee
437 // that it will be effective, regardless of how it's built below.
438 // If raft is to be generated, the 1st top_contact layer will contain the 1st object layer silhouette without holes.
439 SupportGeneratorLayersPtr top_contacts = this->top_contact_layers(object, buildplate_covered, layer_storage);
440 if (top_contacts.empty())
441 // Nothing is supported, no supports are generated.
442 return;
443
444 if (object.print()->canceled())
445 return;
446
447#ifdef SLIC3R_DEBUG
448 static int iRun = 0;
449 iRun ++;
450 for (const SupportGeneratorLayer *layer : top_contacts)
452 debug_out_path("support-top-contacts-%d-%lf.svg", iRun, layer->print_z),
453 union_ex(layer->polygons));
454#endif /* SLIC3R_DEBUG */
455
456 BOOST_LOG_TRIVIAL(info) << "Support generator - Creating bottom contacts";
457
458 // Determine the bottom contact surfaces of the supports over the top surfaces of the object.
459 // Depending on whether the support is soluble or not, the contact layer thickness is decided.
460 // layer_support_areas contains the per object layer support areas. These per object layer support areas
461 // may get merged and trimmed by this->generate_base_layers() if the support layers are not synchronized with object layers.
462 std::vector<Polygons> layer_support_areas;
464 object, top_contacts, buildplate_covered,
465 layer_storage, layer_support_areas);
466
467 if (object.print()->canceled())
468 return;
469
470#ifdef SLIC3R_DEBUG
471 for (size_t layer_id = 0; layer_id < object.layers().size(); ++ layer_id)
473 debug_out_path("support-areas-%d-%lf.svg", iRun, object.layers()[layer_id]->print_z),
474 union_ex(layer_support_areas[layer_id]));
475#endif /* SLIC3R_DEBUG */
476
477 BOOST_LOG_TRIVIAL(info) << "Support generator - Creating intermediate layers - indices";
478
479 // Allocate empty layers between the top / bottom support contact layers
480 // as placeholders for the base and intermediate support layers.
481 // The layers may or may not be synchronized with the object layers, depending on the configuration.
482 // For example, a single nozzle multi material printing will need to generate a waste tower, which in turn
483 // wastes less material, if there are as little tool changes as possible.
485 object, bottom_contacts, top_contacts, layer_storage);
486
487 this->trim_support_layers_by_object(object, top_contacts, m_slicing_params.gap_support_object, m_slicing_params.gap_object_support, m_support_params.gap_xy);
489
490#ifdef SLIC3R_DEBUG
491 for (const SupportGeneratorLayer *layer : top_contacts)
493 debug_out_path("support-top-contacts-trimmed-by-object-%d-%lf.svg", iRun, layer->print_z),
494 union_ex(layer->polygons));
495#endif
496
497 BOOST_LOG_TRIVIAL(info) << "Support generator - Creating base layers";
498
499 // Fill in intermediate layers between the top / bottom support contact layers, trim them by the object.
500 this->generate_base_layers(object, bottom_contacts, top_contacts, intermediate_layers, layer_support_areas);
501
502#ifdef SLIC3R_DEBUG
503 for (SupportGeneratorLayersPtr::const_iterator it = intermediate_layers.begin(); it != intermediate_layers.end(); ++ it)
505 debug_out_path("support-base-layers-%d-%lf.svg", iRun, (*it)->print_z),
506 union_ex((*it)->polygons));
507#endif /* SLIC3R_DEBUG */
508
509 BOOST_LOG_TRIVIAL(info) << "Support generator - Trimming top contacts by bottom contacts";
510
511 // Because the top and bottom contacts are thick slabs, they may overlap causing over extrusion
512 // and unwanted strong bonds to the object.
513 // Rather trim the top contacts by their overlapping bottom contacts to leave a gap instead of over extruding
514 // top contacts over the bottom contacts.
515 this->trim_top_contacts_by_bottom_contacts(object, bottom_contacts, top_contacts);
516
517
518 BOOST_LOG_TRIVIAL(info) << "Support generator - Creating interfaces";
519
520 // Propagate top / bottom contact layers to generate interface layers
521 // and base interface layers (for soluble interface / non souble base only)
522 SupportGeneratorLayersPtr empty_layers;
523 auto [interface_layers, base_interface_layers] = generate_interface_layers(*m_object_config, m_support_params, bottom_contacts, top_contacts, empty_layers, empty_layers, intermediate_layers, layer_storage);
524
525 BOOST_LOG_TRIVIAL(info) << "Support generator - Creating raft";
526
527 // If raft is to be generated, the 1st top_contact layer will contain the 1st object layer silhouette with holes filled.
528 // There is also a 1st intermediate layer containing bases of support columns.
529 // Inflate the bases of the support columns and create the raft base under the object.
530 SupportGeneratorLayersPtr raft_layers = generate_raft_base(object, m_support_params, m_slicing_params, top_contacts, interface_layers, base_interface_layers, intermediate_layers, layer_storage);
531
532 if (object.print()->canceled())
533 return;
534
535#ifdef SLIC3R_DEBUG
536 for (const SupportGeneratorLayer *l : interface_layers)
538 debug_out_path("support-interface-layers-%d-%lf.svg", iRun, l->print_z),
539 union_ex(l->polygons));
540 for (const SupportGeneratorLayer *l : base_interface_layers)
542 debug_out_path("support-base-interface-layers-%d-%lf.svg", iRun, l->print_z),
543 union_ex(l->polygons));
544#endif // SLIC3R_DEBUG
545
546/*
547 // Clip with the pillars.
548 if (! shape.empty()) {
549 this->clip_with_shape(interface, shape);
550 this->clip_with_shape(base, shape);
551 }
552*/
553
554 BOOST_LOG_TRIVIAL(info) << "Support generator - Creating layers";
555
557 object, raft_layers, bottom_contacts, top_contacts, intermediate_layers,
558 interface_layers, base_interface_layers);
559
560// For debugging purposes, one may want to show only some of the support extrusions.
561// raft_layers.clear();
562// bottom_contacts.clear();
563// top_contacts.clear();
564// intermediate_layers.clear();
565// interface_layers.clear();
566
567#ifdef SLIC3R_DEBUG
568 SupportGeneratorLayersPtr layers_sorted =
569#endif // SLIC3R_DEBUG
570 generate_support_layers(object, raft_layers, bottom_contacts, top_contacts, intermediate_layers, interface_layers, base_interface_layers);
571
572 BOOST_LOG_TRIVIAL(info) << "Support generator - Generating tool paths";
573
574#if 0 // #ifdef SLIC3R_DEBUG
575 {
576 size_t layer_id = 0;
577 for (int i = 0; i < int(layers_sorted.size());) {
578 // Find the last layer with roughly the same print_z, find the minimum layer height of all.
579 // Due to the floating point inaccuracies, the print_z may not be the same even if in theory they should.
580 int j = i + 1;
581 coordf_t zmax = layers_sorted[i]->print_z + EPSILON;
582 bool empty = true;
583 for (; j < layers_sorted.size() && layers_sorted[j]->print_z <= zmax; ++j)
584 if (!layers_sorted[j]->polygons.empty())
585 empty = false;
586 if (!empty) {
587 export_print_z_polygons_to_svg(
588 debug_out_path("support-%d-%lf-before.svg", iRun, layers_sorted[i]->print_z).c_str(),
589 layers_sorted.data() + i, j - i);
590 export_print_z_polygons_and_extrusions_to_svg(
591 debug_out_path("support-w-fills-%d-%lf-before.svg", iRun, layers_sorted[i]->print_z).c_str(),
592 layers_sorted.data() + i, j - i,
593 *object.support_layers()[layer_id]);
594 ++layer_id;
595 }
596 i = j;
597 }
598 }
599#endif /* SLIC3R_DEBUG */
600
601 // Generate the actual toolpaths and save them into each layer.
602 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);
603
604#ifdef SLIC3R_DEBUG
605 {
606 size_t layer_id = 0;
607 for (int i = 0; i < int(layers_sorted.size());) {
608 // Find the last layer with roughly the same print_z, find the minimum layer height of all.
609 // Due to the floating point inaccuracies, the print_z may not be the same even if in theory they should.
610 int j = i + 1;
611 coordf_t zmax = layers_sorted[i]->print_z + EPSILON;
612 bool empty = true;
613 for (; j < layers_sorted.size() && layers_sorted[j]->print_z <= zmax; ++j)
614 if (! layers_sorted[j]->polygons.empty())
615 empty = false;
616 if (! empty) {
617 export_print_z_polygons_to_svg(
618 debug_out_path("support-%d-%lf.svg", iRun, layers_sorted[i]->print_z).c_str(),
619 layers_sorted.data() + i, j - i);
620 export_print_z_polygons_and_extrusions_to_svg(
621 debug_out_path("support-w-fills-%d-%lf.svg", iRun, layers_sorted[i]->print_z).c_str(),
622 layers_sorted.data() + i, j - i,
623 *object.support_layers()[layer_id]);
624 ++layer_id;
625 }
626 i = j;
627 }
628 }
629#endif /* SLIC3R_DEBUG */
630
631 BOOST_LOG_TRIVIAL(info) << "Support generator - End";
632}
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:2759
SupportGeneratorLayersPtr top_contact_layers(const PrintObject &object, const std::vector< Polygons > &buildplate_covered, SupportGeneratorLayerStorage &layer_storage) const
Definition SupportMaterial.cpp:2186
SupportGeneratorLayersPtr raft_and_intermediate_support_layers(const PrintObject &object, const SupportGeneratorLayersPtr &bottom_contacts, const SupportGeneratorLayersPtr &top_contacts, SupportGeneratorLayerStorage &layer_storage) const
Definition SupportMaterial.cpp:2956
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:3149
void trim_top_contacts_by_bottom_contacts(const PrintObject &object, const SupportGeneratorLayersPtr &bottom_contacts, SupportGeneratorLayersPtr &top_contacts) const
Definition SupportMaterial.cpp:2931
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:381
std::string debug_out_path(const char *name,...)
Definition utils.cpp:382
double coordf_t
Definition GUI_ObjectList.hpp:46
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:194
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:404
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:1549
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:1467
Slic3r::ExPolygons union_ex(const Slic3r::Polygons &subject, PolyFillType fill_type)
Definition ClipperUtils.cpp:1011
bool empty(const BoundingBoxBase< PointType, PointsType > &bb)
Definition BoundingBox.hpp:273
void trim_support_layers_by_exclusion_volumes(const 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:141

References bottom_contact_layers_and_layer_support_areas(), buildplate_covered(), Slic3r::debug_out_path(), Slic3r::empty(), EPSILON, Slic3r::SVG::export_expolygons(), generate_base_layers(), Slic3r::generate_interface_layers(), Slic3r::generate_raft_base(), Slic3r::generate_support_layers(), Slic3r::generate_support_toolpaths(), m_object_config, m_print_config, m_slicing_params, m_support_params, raft_and_intermediate_support_layers(), top_contact_layers(), Slic3r::trim_support_layers_by_belt_floor(), Slic3r::trim_support_layers_by_exclusion_volumes(), 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
3155{
3156#ifdef SLIC3R_DEBUG
3157 static int iRun = 0;
3158#endif /* SLIC3R_DEBUG */
3159
3160 if (top_contacts.empty())
3161 // No top contacts -> no intermediate layers will be produced.
3162 return;
3163
3164 BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::generate_base_layers() in parallel - start";
3165 tbb::parallel_for(
3166 tbb::blocked_range<size_t>(0, intermediate_layers.size()),
3167 [&object, &bottom_contacts, &top_contacts, &intermediate_layers, &layer_support_areas](const tbb::blocked_range<size_t>& range) {
3168 // index -2 means not initialized yet, -1 means intialized and decremented to 0 and then -1.
3169 int idx_top_contact_above = -2;
3170 int idx_bottom_contact_overlapping = -2;
3171 int idx_object_layer_above = -2;
3172 // Counting down due to the way idx_lower_or_equal caches indices to avoid repeated binary search over the complete sequence.
3173 for (int idx_intermediate = int(range.end()) - 1; idx_intermediate >= int(range.begin()); -- idx_intermediate)
3174 {
3175 BOOST_LOG_TRIVIAL(trace) << "Support generator - generate_base_layers - creating layer " <<
3176 idx_intermediate << " of " << intermediate_layers.size();
3177 SupportGeneratorLayer &layer_intermediate = *intermediate_layers[idx_intermediate];
3178 // Layers must be sorted by print_z.
3179 assert(idx_intermediate == 0 || layer_intermediate.print_z >= intermediate_layers[idx_intermediate - 1]->print_z);
3180
3181 // Find a top_contact layer touching the layer_intermediate from above, if any, and collect its polygons into polygons_new.
3182 // New polygons for layer_intermediate.
3183 Polygons polygons_new;
3184
3185 // Use the precomputed layer_support_areas. "idx_object_layer_above": above means above since the last iteration, not above after this call.
3186 idx_object_layer_above = idx_lower_or_equal(object.layers().begin(), object.layers().end(), idx_object_layer_above,
3187 [&layer_intermediate](const Layer* layer) { return layer->print_z <= layer_intermediate.print_z + EPSILON; });
3188
3189 // Polygons to trim polygons_new.
3190 Polygons polygons_trimming;
3191
3192 // Trimming the base layer with any overlapping top layer.
3193 // Following cases are recognized:
3194 // 1) top.bottom_z >= base.top_z -> No overlap, no trimming needed.
3195 // 2) base.bottom_z >= top.print_z -> No overlap, no trimming needed.
3196 // 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.
3197 // 4) base.print_z > top.bottom_z && base.bottom_z < top.bottom_z -> Base overlaps with top.bottom_z. This must not happen.
3198 // 5) base.print_z <= top.print_z && base.bottom_z >= top.bottom_z -> Base is fully inside top. Trim base by top.
3199 idx_top_contact_above = idx_lower_or_equal(top_contacts, idx_top_contact_above,
3200 [&layer_intermediate](const SupportGeneratorLayer *layer){ return layer->bottom_z <= layer_intermediate.print_z - EPSILON; });
3201 // Collect all the top_contact layer intersecting with this layer.
3202 for (int idx_top_contact_overlapping = idx_top_contact_above; idx_top_contact_overlapping >= 0; -- idx_top_contact_overlapping) {
3203 SupportGeneratorLayer &layer_top_overlapping = *top_contacts[idx_top_contact_overlapping];
3204 if (layer_top_overlapping.print_z < layer_intermediate.bottom_z + EPSILON)
3205 break;
3206 // Base must not overlap with top.bottom_z.
3207 assert(! (layer_intermediate.print_z > layer_top_overlapping.bottom_z + EPSILON && layer_intermediate.bottom_z < layer_top_overlapping.bottom_z - EPSILON));
3208 if (layer_intermediate.print_z <= layer_top_overlapping.print_z + EPSILON && layer_intermediate.bottom_z >= layer_top_overlapping.bottom_z - EPSILON)
3209 // Base is fully inside top. Trim base by top.
3210 polygons_append(polygons_trimming, layer_top_overlapping.polygons);
3211 }
3212
3213 if (idx_object_layer_above < 0) {
3214 // layer_support_areas are synchronized with object layers and they contain projections of the contact layers above them.
3215 // This intermediate layer is not above any object layer, thus there is no information in layer_support_areas about
3216 // towers supporting contact layers intersecting the first object layer. Project these contact layers now.
3217 polygons_new = layer_support_areas.front();
3218 double first_layer_z = object.layers().front()->print_z;
3219 for (int i = idx_top_contact_above + 1; i < int(top_contacts.size()); ++ i) {
3220 SupportGeneratorLayer &contacts = *top_contacts[i];
3221 if (contacts.print_z > first_layer_z + EPSILON)
3222 break;
3223 assert(contacts.bottom_z > layer_intermediate.print_z - EPSILON);
3224 polygons_append(polygons_new, contacts.polygons);
3225 }
3226 } else
3227 polygons_new = layer_support_areas[idx_object_layer_above];
3228
3229 // Trimming the base layer with any overlapping bottom layer.
3230 // Following cases are recognized:
3231 // 1) bottom.bottom_z >= base.top_z -> No overlap, no trimming needed.
3232 // 2) base.bottom_z >= bottom.print_z -> No overlap, no trimming needed.
3233 // 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.
3234 // 4) base.print_z > bottom.print_z && base.bottom_z >= bottom.print_z -> Base overlaps with bottom.print_z. This must not happen.
3235 // 5) base.print_z <= bottom.print_z && base.bottom_z >= bottom.bottom_z -> Base is fully inside top. Trim base by top.
3236 idx_bottom_contact_overlapping = idx_lower_or_equal(bottom_contacts, idx_bottom_contact_overlapping,
3237 [&layer_intermediate](const SupportGeneratorLayer *layer){ return layer->bottom_print_z() <= layer_intermediate.print_z - EPSILON; });
3238 // Collect all the bottom_contacts layer intersecting with this layer.
3239 for (int i = idx_bottom_contact_overlapping; i >= 0; -- i) {
3240 SupportGeneratorLayer &layer_bottom_overlapping = *bottom_contacts[i];
3241 if (layer_bottom_overlapping.print_z < layer_intermediate.bottom_print_z() + EPSILON)
3242 break;
3243 // Base must not overlap with bottom.top_z.
3244 assert(! (layer_intermediate.print_z > layer_bottom_overlapping.print_z + EPSILON && layer_intermediate.bottom_z < layer_bottom_overlapping.print_z - EPSILON));
3245 if (layer_intermediate.print_z <= layer_bottom_overlapping.print_z + EPSILON && layer_intermediate.bottom_z >= layer_bottom_overlapping.bottom_print_z() - EPSILON)
3246 // Base is fully inside bottom. Trim base by bottom.
3247 polygons_append(polygons_trimming, layer_bottom_overlapping.polygons);
3248 }
3249
3250 #ifdef SLIC3R_DEBUG
3251 {
3252 BoundingBox bbox = get_extents(polygons_new);
3253 bbox.merge(get_extents(polygons_trimming));
3254 ::Slic3r::SVG svg(debug_out_path("support-intermediate-layers-raw-%d-%lf.svg", iRun, layer_intermediate.print_z), bbox);
3255 svg.draw(union_ex(polygons_new), "blue", 0.5f);
3256 svg.draw(to_polylines(polygons_new), "blue");
3257 svg.draw(union_safety_offset_ex(polygons_trimming), "red", 0.5f);
3258 svg.draw(to_polylines(polygons_trimming), "red");
3259 }
3260 #endif /* SLIC3R_DEBUG */
3261
3262 // Trim the polygons, store them.
3263 if (polygons_trimming.empty())
3264 layer_intermediate.polygons = std::move(polygons_new);
3265 else
3266 layer_intermediate.polygons = diff(
3267 polygons_new,
3268 polygons_trimming,
3269 ApplySafetyOffset::Yes); // safety offset to merge the touching source polygons
3270 layer_intermediate.layer_type = SupporLayerType::Base;
3271
3272 #if 0
3273 // coordf_t fillet_radius_scaled = scale_(m_object_config->support_base_pattern_spacing);
3274 // Fillet the base polygons and trim them again with the top, interface and contact layers.
3275 $base->{$i} = diff(
3276 offset2(
3277 $base->{$i},
3278 $fillet_radius_scaled,
3279 -$fillet_radius_scaled,
3280 # Use a geometric offsetting for filleting.
3281 JT_ROUND,
3282 0.2*$fillet_radius_scaled),
3283 $trim_polygons,
3284 false); // don't apply the safety offset.
3285 }
3286 #endif
3287 }
3288 });
3289 BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::generate_base_layers() in parallel - end";
3290
3291#ifdef SLIC3R_DEBUG
3292 for (SupportGeneratorLayersPtr::const_iterator it = intermediate_layers.begin(); it != intermediate_layers.end(); ++it)
3294 debug_out_path("support-intermediate-layers-untrimmed-%d-%lf.svg", iRun, (*it)->print_z),
3295 union_ex((*it)->polygons));
3296 ++ iRun;
3297#endif /* SLIC3R_DEBUG */
3298
3299 this->trim_support_layers_by_object(object, intermediate_layers, m_slicing_params.gap_support_object, m_slicing_params.gap_object_support, m_support_params.gap_xy);
3301}
auto range(Cont &&cont)
Definition libslic3r.h:405

References generate_base_layers(), and Slic3r::range().

Referenced by generate(), and generate_base_layers().

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
34{ return m_object_config->support_interface_loop_pattern.value; }

References m_object_config.

◆ has_raft()

bool Slic3r::PrintObjectSupportMaterial::has_raft ( ) const
inline
28{ return m_slicing_params.has_raft(); }

References m_slicing_params.

Referenced by top_contact_layers().

Here is the caller graph for this function:

◆ has_support()

bool Slic3r::PrintObjectSupportMaterial::has_support ( ) const
inline
30{ return m_object_config->enable_support.value || m_object_config->enforce_support_layers; }

References m_object_config.

Referenced by build_plate_only(), and top_contact_layers().

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
2961{
2962 SupportGeneratorLayersPtr intermediate_layers;
2963
2964 // Collect and sort the extremes (bottoms of the top contacts and tops of the bottom contacts).
2966 extremes.reserve(top_contacts.size() + bottom_contacts.size());
2967 for (size_t i = 0; i < top_contacts.size(); ++ i)
2968 // Bottoms of the top contact layers. In case of non-soluble supports,
2969 // the top contact layer thickness is not known yet.
2970 extremes.push_back(top_contacts[i]);
2971 for (size_t i = 0; i < bottom_contacts.size(); ++ i)
2972 // Tops of the bottom contact layers.
2973 extremes.push_back(bottom_contacts[i]);
2974 if (extremes.empty())
2975 return intermediate_layers;
2976
2977 auto layer_extreme_lower = [](const SupportGeneratorLayer *l1, const SupportGeneratorLayer *l2) {
2978 coordf_t z1 = l1->extreme_z();
2979 coordf_t z2 = l2->extreme_z();
2980 // If the layers are aligned, return the top contact surface first.
2981 return z1 < z2 || (z1 == z2 && l1->layer_type == SupporLayerType::TopContact && l2->layer_type == SupporLayerType::BottomContact);
2982 };
2983 std::sort(extremes.begin(), extremes.end(), layer_extreme_lower);
2984
2985 assert(extremes.empty() ||
2986 (extremes.front()->extreme_z() > m_slicing_params.raft_interface_top_z - EPSILON &&
2987 (m_slicing_params.raft_layers() == 1 || // only raft contact layer
2988 extremes.front()->layer_type == SupporLayerType::TopContact || // first extreme is a top contact layer
2989 extremes.front()->extreme_z() > m_slicing_params.first_print_layer_height - EPSILON)));
2990
2991 bool synchronize = this->synchronize_layers();
2992
2993#ifdef _DEBUG
2994 // Verify that the extremes are separated by m_support_layer_height_min.
2995 for (size_t i = 1; i < extremes.size(); ++ i) {
2996 assert(extremes[i]->extreme_z() - extremes[i-1]->extreme_z() == 0. ||
2997 extremes[i]->extreme_z() - extremes[i-1]->extreme_z() > m_support_params.support_layer_height_min - EPSILON);
2998 assert(extremes[i]->extreme_z() - extremes[i-1]->extreme_z() > 0. ||
2999 extremes[i]->layer_type == extremes[i-1]->layer_type ||
3000 (extremes[i]->layer_type == SupporLayerType::BottomContact && extremes[i - 1]->layer_type == SupporLayerType::TopContact));
3001 }
3002#endif
3003
3004 // Generate intermediate layers.
3005 // The first intermediate layer is the same as the 1st layer if there is no raft,
3006 // or the bottom of the first intermediate layer is aligned with the bottom of the raft contact layer.
3007 // Intermediate layers are always printed with a normal extrusion flow (non-bridging).
3008 size_t idx_layer_object = 0;
3009 size_t idx_extreme_first = 0;
3010 if (! extremes.empty() && std::abs(extremes.front()->extreme_z() - m_slicing_params.raft_interface_top_z) < EPSILON) {
3011 // This is a raft contact layer, its height has been decided in this->top_contact_layers().
3012 // Ignore this layer when calculating the intermediate support layers.
3013 assert(extremes.front()->layer_type == SupporLayerType::TopContact);
3014 ++ idx_extreme_first;
3015 }
3016 for (size_t idx_extreme = idx_extreme_first; idx_extreme < extremes.size(); ++ idx_extreme) {
3017 SupportGeneratorLayer *extr2 = extremes[idx_extreme];
3018 coordf_t extr2z = extr2->extreme_z();
3019 if (std::abs(extr2z - m_slicing_params.first_print_layer_height) < EPSILON) {
3020 // This is a bottom of a synchronized (or soluble) top contact layer, its height has been decided in this->top_contact_layers().
3021 assert(extr2->layer_type == SupporLayerType::TopContact);
3022 assert(std::abs(extr2->bottom_z - m_slicing_params.first_print_layer_height) < EPSILON);
3023 assert(extr2->print_z >= m_slicing_params.first_print_layer_height + m_support_params.support_layer_height_min - EPSILON);
3024 if (intermediate_layers.empty() || intermediate_layers.back()->print_z < m_slicing_params.first_print_layer_height) {
3025 SupportGeneratorLayer &layer_new = layer_storage.allocate(SupporLayerType::Intermediate);
3026 layer_new.bottom_z = 0.;
3027 layer_new.print_z = m_slicing_params.first_print_layer_height;
3028 layer_new.height = m_slicing_params.first_print_layer_height;
3029 intermediate_layers.push_back(&layer_new);
3030 }
3031 continue;
3032 }
3033 assert(extr2z >= m_slicing_params.raft_interface_top_z + EPSILON);
3034 assert(extr2z >= m_slicing_params.first_print_layer_height + EPSILON);
3035 SupportGeneratorLayer *extr1 = (idx_extreme == idx_extreme_first) ? nullptr : extremes[idx_extreme - 1];
3036 // Fuse a support layer firmly to the raft top interface (not to the raft contacts).
3037 coordf_t extr1z = (extr1 == nullptr) ? m_slicing_params.raft_interface_top_z : extr1->extreme_z();
3038 assert(extr2z >= extr1z);
3039 assert(extr2z > extr1z || (extr1 != nullptr && extr2->layer_type == SupporLayerType::BottomContact));
3040 if (std::abs(extr1z) < EPSILON) {
3041 // This layer interval starts with the 1st layer. Print the 1st layer using the prescribed 1st layer thickness.
3042 // assert(! m_slicing_params.has_raft()); RaftingEdition: unclear where the issue is: assert fails with 1-layer raft & base supports
3043 assert(intermediate_layers.empty() || intermediate_layers.back()->print_z <= m_slicing_params.first_print_layer_height);
3044 // At this point only layers above first_print_layer_heigth + EPSILON are expected as the other cases were captured earlier.
3045 assert(extr2z >= m_slicing_params.first_print_layer_height + EPSILON);
3046 // Generate a new intermediate layer.
3047 SupportGeneratorLayer &layer_new = layer_storage.allocate(SupporLayerType::Intermediate);
3048 layer_new.bottom_z = 0.;
3049 layer_new.print_z = extr1z = m_slicing_params.first_print_layer_height;
3050 layer_new.height = extr1z;
3051 intermediate_layers.push_back(&layer_new);
3052 // Continue printing the other layers up to extr2z.
3053 }
3054 coordf_t dist = extr2z - extr1z;
3055 assert(dist >= 0.);
3056 if (dist == 0.)
3057 continue;
3058 // The new layers shall be at least m_support_layer_height_min thick.
3059 assert(dist >= m_support_params.support_layer_height_min - EPSILON);
3060 if (synchronize) {
3061 // Emit support layers synchronized with the object layers.
3062 // Find the first object layer, which has its print_z in this support Z range.
3063 while (idx_layer_object < object.layers().size() && object.layers()[idx_layer_object]->print_z < extr1z + EPSILON)
3064 ++ idx_layer_object;
3065 if (idx_layer_object == 0 && extr1z == m_slicing_params.raft_interface_top_z) {
3066 // Insert one base support layer below the object.
3067 SupportGeneratorLayer &layer_new = layer_storage.allocate(SupporLayerType::Intermediate);
3068 layer_new.print_z = m_slicing_params.object_print_z_min;
3069 layer_new.bottom_z = m_slicing_params.raft_interface_top_z;
3070 layer_new.height = layer_new.print_z - layer_new.bottom_z;
3071 intermediate_layers.push_back(&layer_new);
3072 }
3073 // Emit all intermediate support layers synchronized with object layers up to extr2z.
3074 for (; idx_layer_object < object.layers().size() && object.layers()[idx_layer_object]->print_z < extr2z + EPSILON; ++ idx_layer_object) {
3075 SupportGeneratorLayer &layer_new = layer_storage.allocate(SupporLayerType::Intermediate);
3076 layer_new.print_z = object.layers()[idx_layer_object]->print_z;
3077 layer_new.height = object.layers()[idx_layer_object]->height;
3078 layer_new.bottom_z = (idx_layer_object > 0) ? object.layers()[idx_layer_object - 1]->print_z : (layer_new.print_z - layer_new.height);
3079 assert(intermediate_layers.empty() || intermediate_layers.back()->print_z < layer_new.print_z + EPSILON);
3080 intermediate_layers.push_back(&layer_new);
3081 }
3082 } else {
3083 // ORCA: Bias by EPSILON so a gap effectively equal to
3084 // max_suport_layer_height is not split by floating-point noise.
3085 size_t n_layers_extra = size_t(ceil((dist - EPSILON) / m_slicing_params.max_suport_layer_height));
3086 assert(n_layers_extra > 0);
3087 coordf_t step = dist / coordf_t(n_layers_extra);
3088 if (extr1 != nullptr && extr1->layer_type == SupporLayerType::TopContact &&
3089 extr1->print_z + m_support_params.support_layer_height_min > extr1->bottom_z + step) {
3090 // The bottom extreme is a bottom of a top surface. Ensure that the gap
3091 // between the 1st intermediate layer print_z and extr1->print_z is not too small.
3092 assert(extr1->bottom_z + m_support_params.support_layer_height_min < extr1->print_z + EPSILON);
3093 // Generate the first intermediate layer.
3094 SupportGeneratorLayer &layer_new = layer_storage.allocate(SupporLayerType::Intermediate);
3095 layer_new.bottom_z = extr1->bottom_z;
3096 layer_new.print_z = extr1z = extr1->print_z;
3097 layer_new.height = extr1->height;
3098 intermediate_layers.push_back(&layer_new);
3099 dist = extr2z - extr1z;
3100 // ORCA: Recalculate with the same EPSILON bias after re-anchoring at the top
3101 // contact layer so near-equal gaps do not gain an extra split here either.
3102 n_layers_extra = size_t(ceil((dist - EPSILON) / m_slicing_params.max_suport_layer_height));
3103 if (n_layers_extra == 0)
3104 continue;
3105 // Continue printing the other layers up to extr2z.
3106 step = dist / coordf_t(n_layers_extra);
3107 }
3108 if (!m_slicing_params.zero_gap_interface_top && extr2->layer_type == SupporLayerType::TopContact) {
3109 // This is a top interface layer, which does not have a height assigned yet. Do it now.
3110 assert(extr2->height == 0.);
3111 assert(extr1z > m_slicing_params.first_print_layer_height - EPSILON);
3112 extr2->height = step;
3113 extr2->bottom_z = extr2z = extr2->print_z - step;
3114 if (-- n_layers_extra == 0)
3115 continue;
3116 }
3117 coordf_t extr2z_large_steps = extr2z;
3118 // Take the largest allowed step in the Z axis until extr2z_large_steps is reached.
3119 for (size_t i = 0; i < n_layers_extra; ++ i) {
3120 SupportGeneratorLayer &layer_new = layer_storage.allocate(SupporLayerType::Intermediate);
3121 if (i + 1 == n_layers_extra) {
3122 // Last intermediate layer added. Align the last entered layer with extr2z_large_steps exactly.
3123 layer_new.bottom_z = (i == 0) ? extr1z : intermediate_layers.back()->print_z;
3124 layer_new.print_z = extr2z_large_steps;
3125 layer_new.height = layer_new.print_z - layer_new.bottom_z;
3126 }
3127 else {
3128 // Intermediate layer, not the last added.
3129 layer_new.height = step;
3130 layer_new.bottom_z = extr1z + i * step;
3131 layer_new.print_z = layer_new.bottom_z + step;
3132 }
3133 assert(intermediate_layers.empty() || intermediate_layers.back()->print_z <= layer_new.print_z);
3134 intermediate_layers.push_back(&layer_new);
3135 }
3136 }
3137 }
3138
3139#ifdef _DEBUG
3140 for (size_t i = 0; i < top_contacts.size(); ++i)
3141 assert(top_contacts[i]->height > 0.);
3142#endif /* _DEBUG */
3143
3144 return intermediate_layers;
3145}
bool synchronize_layers() const
Definition SupportMaterial.hpp:33
T dist(const boost::polygon::point_data< T > &p1, const boost::polygon::point_data< T > &p2)
Definition Geometry.cpp:298
@ BottomContact
Definition SupportLayer.hpp:26
@ Intermediate
Definition SupportLayer.hpp:38
@ TopContact
Definition SupportLayer.hpp:36
T l2(const boost::geometry::model::d2::point_xy< T > &v)
Definition ExtrusionSimulator.cpp:177
void step(Coord &crd, const Dir d, const long n=1)
Definition MarchingSquares.hpp:213

References Slic3r::SupportGeneratorLayerStorage::allocate(), Slic3r::SupportGeneratorLayer::bottom_z, Slic3r::BottomContact, Slic3r::Geometry::dist(), EPSILON, Slic3r::SupportGeneratorLayer::extreme_z(), Slic3r::SupportGeneratorLayer::height, Slic3r::Intermediate, Slic3r::l2(), Slic3r::SupportGeneratorLayer::layer_type, m_slicing_params, m_support_params, Slic3r::SupportGeneratorLayer::print_z, raft_and_intermediate_support_layers(), synchronize_layers(), and Slic3r::TopContact.

Referenced by generate(), and raft_and_intermediate_support_layers().

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
33{ return /*m_slicing_params.zero_gap_interface_top && */!m_print_config->independent_support_layer_height.value; }

References m_print_config.

Referenced by raft_and_intermediate_support_layers().

Here is the caller graph for this function:

◆ top_contact_layers()

SupportGeneratorLayersPtr Slic3r::PrintObjectSupportMaterial::top_contact_layers ( const PrintObject & object,
const std::vector< Polygons > & buildplate_covered,
SupportGeneratorLayerStorage & layer_storage ) const
private
2188{
2189#ifdef SLIC3R_DEBUG
2190 static int iRun = 0;
2191 ++ iRun;
2192 #define SLIC3R_IRUN , iRun
2193#endif /* SLIC3R_DEBUG */
2194
2195 // BBS: tree support is selected so normal supports need not be generated.
2196 // Note we still need to go through the following steps if support is disabled but raft is enabled.
2197 if (m_object_config->enable_support.value && (m_object_config->support_type.value != stNormalAuto && m_object_config->support_type.value != stNormal)) {
2199 }
2200
2201 // Slice support enforcers / support blockers.
2202 SupportAnnotations annotations(object, buildplate_covered);
2203
2204 // Output layers, sorted by top Z.
2205 SupportGeneratorLayersPtr contact_out;
2206
2207 BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::top_contact_layers() in parallel - start";
2208 // Determine top contact areas.
2209 // If generating raft only (no support), only calculate top contact areas for the 0th layer.
2210 // If having a raft, start with 0th layer, otherwise with 1st layer.
2211 // Note that layer_id < layer->id when raft_layers > 0 as the layer->id incorporates the raft layers.
2212 // So layer_id == 0 means first object layer and layer->id == 0 means first print layer if there are no explicit raft layers.
2213 size_t num_layers = this->has_support() ? object.layer_count() : 1;
2214 // For each overhang layer, two supporting layers may be generated: One for the overhangs extruded with a bridging flow,
2215 // and the other for the overhangs extruded with a normal flow.
2216 contact_out.assign(num_layers * 2, nullptr);
2217
2218 std::vector<ExPolygons> overhangs_per_layers(num_layers);
2219 size_t layer_id_start = this->has_raft() ? 0 : 1;
2220 // main part of overhang detection can be parallel
2221 tbb::parallel_for(tbb::blocked_range<size_t>(layer_id_start, num_layers),
2222 [&](const tbb::blocked_range<size_t>& range) {
2223 for (size_t layer_id = range.begin(); layer_id < range.end(); layer_id++) {
2224 const Layer& layer = *object.layers()[layer_id];
2225 Polygons lower_layer_polygons = (layer_id == 0) ? Polygons() : to_polygons(object.layers()[layer_id - 1]->lslices);
2226
2227 overhangs_per_layers[layer_id] = detect_overhangs(layer, layer_id, lower_layer_polygons, *m_print_config, *m_object_config, annotations, m_support_params.gap_xy
2228#ifdef SLIC3R_DEBUG
2229 , iRun
2230#endif // SLIC3R_DEBUG
2231 );
2232
2233 if (object.print()->canceled())
2234 break;
2235 }
2236 }
2237 ); // end tbb::parallel_for
2238
2239 if (object.print()->canceled())
2241
2242 // check if the sharp tails should be extended higher
2243 bool detect_first_sharp_tail_only = false;
2244 const coordf_t extrusion_width = m_object_config->line_width.get_abs_value(nozzle_diameter_for_filament(object.print()->config(), object.config().support_interface_filament, object.print()->is_BBL_printer()));
2245 const coordf_t extrusion_width_scaled = scale_(extrusion_width);
2246 if (is_auto(m_object_config->support_type.value) && g_config_support_sharp_tails && !detect_first_sharp_tail_only) {
2247 for (size_t layer_nr = layer_id_start; layer_nr < num_layers; layer_nr++) {
2248 if (object.print()->canceled())
2249 break;
2250
2251 const Layer* layer = object.get_layer(layer_nr);
2252 const Layer* lower_layer = layer->lower_layer;
2253 if (!lower_layer)
2254 continue;
2255
2256 // BBS detect sharp tail
2257 const ExPolygons& lower_layer_sharptails = lower_layer->sharp_tails;
2258 const auto& lower_layer_sharptails_height = lower_layer->sharp_tails_height;
2259 for (const ExPolygon& expoly : layer->lslices) {
2260 bool is_sharp_tail = false;
2261 float accum_height = layer->height;
2262 do {
2263 // 2. something below
2264 // check whether this is above a sharp tail region.
2265
2266 // 2.1 If no sharp tail below, this is considered as common region.
2267 ExPolygons supported_by_lower = intersection_ex({ expoly }, lower_layer_sharptails);
2268 if (supported_by_lower.empty()) {
2269 is_sharp_tail = false;
2270 break;
2271 }
2272
2273 // 2.2 If sharp tail below, check whether it support this region enough.
2274#if 0
2275 // judge by area isn't reliable, failure cases include 45 degree rotated cube
2276 float supported_area = area(supported_by_lower);
2277 if (supported_area > area_thresh_well_supported) {
2278 is_sharp_tail = false;
2279 break;
2280 }
2281#endif
2282 BoundingBox bbox = get_extents(supported_by_lower);
2283 if (bbox.size().x() > length_thresh_well_supported && bbox.size().y() > length_thresh_well_supported) {
2284 is_sharp_tail = false;
2285 break;
2286 }
2287
2288 // 2.3 check whether sharp tail exceed the max height
2289 for (size_t i = 0; i < lower_layer_sharptails_height.size();i++) {
2290 if (lower_layer_sharptails[i].overlaps(expoly)) {
2291 accum_height += lower_layer_sharptails_height[i];
2292 break;
2293 }
2294 }
2295 if (accum_height > sharp_tail_max_support_height) {
2296 is_sharp_tail = false;
2297 break;
2298 }
2299
2300 // 2.4 if the area grows fast than threshold, it get connected to other part or
2301 // it has a sharp slop and will be auto supported.
2302 ExPolygons new_overhang_expolys = diff_ex({ expoly }, lower_layer_sharptails);
2303 Point size_diff = get_extents(new_overhang_expolys).size() - get_extents(lower_layer_sharptails).size();
2304 if (size_diff.both_comp(Point(scale_(5), scale_(5)), ">") || !offset_ex(new_overhang_expolys, -5.0 * extrusion_width_scaled).empty()) {
2305 is_sharp_tail = false;
2306 break;
2307 }
2308
2309 // 2.5 mark the expoly as sharptail
2310 is_sharp_tail = true;
2311 } while (0);
2312
2313 if (is_sharp_tail) {
2314 ExPolygons overhang = diff_ex({ expoly }, lower_layer->lslices);
2315 layer->sharp_tails.push_back(expoly);
2316 layer->sharp_tails_height.push_back( accum_height );
2317
2318 // Apply the "support blockers".
2319 if (!annotations.blockers_layers.empty() && !annotations.blockers_layers[layer_nr].empty()) {
2320 const auto& blocker = annotations.blockers_layers[layer_nr];
2321 overhang = diff_ex(overhang, blocker);
2322 }
2323
2324 append(overhangs_per_layers[layer_nr], overhang);
2325 }
2326
2327 }
2328 }
2329 }
2330
2331 if (object.print()->canceled())
2333
2334 // BBS group overhang clusters
2335 const bool config_remove_small_overhangs = m_object_config->support_remove_small_overhang.value;
2336 if (config_remove_small_overhangs) {
2337 std::vector<OverhangCluster> clusters;
2338 double fw_scaled = scale_(extrusion_width);
2339 std::set<ExPolygon*> removed_overhang;
2340
2341 for (size_t layer_id = layer_id_start; layer_id < num_layers; layer_id++) {
2342 const Layer* layer = object.get_layer(layer_id);
2343 for (auto& overhang : overhangs_per_layers[layer_id]) {
2344 OverhangCluster* cluster = add_overhang(clusters, &overhang, layer_id, fw_scaled);
2345 if (overlaps({ overhang }, layer->cantilevers))
2346 cluster->is_cantilever = true;
2347 }
2348 }
2349
2350 for (OverhangCluster& cluster : clusters) {
2351 // 3. check whether the small overhang is sharp tail
2352 cluster.is_sharp_tail = false;
2353 for (size_t layer_id = cluster.min_layer; layer_id <= cluster.max_layer; layer_id++) {
2354 const Layer* layer = object.get_layer(layer_id);
2355 if (overlaps(layer->sharp_tails, cluster.merged_overhangs_dilated)) {
2356 cluster.is_sharp_tail = true;
2357 break;
2358 }
2359 }
2360
2361 if (!cluster.is_sharp_tail && !cluster.is_cantilever) {
2362 // 2. check overhang cluster size is small
2363 cluster.is_small_overhang = false;
2364 auto erode1 = offset_ex(cluster.merged_overhangs_dilated, -1.0 * fw_scaled);
2365 Point bbox_sz = get_extents(erode1).size();
2366 if (bbox_sz.x() < 2 * fw_scaled || bbox_sz.y() < 2 * fw_scaled) {
2367 cluster.is_small_overhang = true;
2368 }
2369 }
2370
2371#ifdef SUPPORT_TREE_DEBUG_TO_SVG
2372 const Layer* layer1 = object.get_layer(cluster.min_layer);
2373 BoundingBox bbox = get_extents(cluster.merged_overhangs_dilated);
2374 bbox.merge(get_extents(layer1->lslices));
2375 SVG svg(format("SVG/overhangCluster_%s_%s_tail=%s_cantilever=%s_small=%s.svg", cluster.min_layer, layer1->print_z, cluster.is_sharp_tail, cluster.is_cantilever, cluster.is_small_overhang), bbox);
2376 if (svg.is_opened()) {
2377 svg.draw(layer1->lslices, "red");
2378 svg.draw(cluster.merged_overhangs_dilated, "blue");
2379 }
2380#endif
2381
2382 // 5. remove small overhangs
2383 if (cluster.is_small_overhang) {
2384 for (auto overhangs : cluster.layer_overhangs) {
2385 for (auto* poly : overhangs.second)
2386 removed_overhang.insert(poly);
2387 }
2388 }
2389 }
2390
2391 for (size_t layer_id = layer_id_start; layer_id < num_layers; layer_id++) {
2392 auto& layer_overhangs = overhangs_per_layers[layer_id];
2393 if (layer_overhangs.empty())
2394 continue;
2395
2396 for (int poly_idx = 0; poly_idx < layer_overhangs.size(); poly_idx++) {
2397 auto* overhang = &layer_overhangs[poly_idx];
2398 if (removed_overhang.find(overhang) != removed_overhang.end()) {
2399 overhang->clear();
2400 }
2401 }
2402 }
2403 }
2404
2405 if (object.print()->canceled())
2407
2408 for (size_t layer_id = layer_id_start; layer_id < num_layers; layer_id++) {
2409 const Layer& layer = *object.layers()[layer_id];
2410 Polygons overhang_polygons = to_polygons(overhangs_per_layers[layer_id]);
2411 Polygons lower_layer_polygons = (layer_id == 0) ? Polygons() : to_polygons(object.layers()[layer_id - 1]->lslices);
2412 SlicesMarginCache slices_margin;
2413
2414 auto [contact_polygons, enforcer_polygons, no_interface_offset] =
2415 detect_contacts(layer, layer_id, overhang_polygons, lower_layer_polygons, *m_print_config, *m_object_config, annotations, slices_margin, m_support_params.gap_xy
2416#ifdef SLIC3R_DEBUG
2417 , iRun
2418#endif // SLIC3R_DEBUG
2419 );
2420
2421 // Now apply the contact areas to the layer where they need to be made.
2422 if (!contact_polygons.empty() || !overhang_polygons.empty()) {
2423 // Allocate the two empty layers.
2424 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);
2425 if (new_layer) {
2426 // Fill the non-bridging layer with polygons.
2427 fill_contact_layer(*new_layer, layer_id, m_slicing_params,
2428 *m_object_config, slices_margin, overhang_polygons, contact_polygons, enforcer_polygons, lower_layer_polygons,
2429 m_support_params.support_material_flow, no_interface_offset
2430#ifdef SLIC3R_DEBUG
2431 , iRun, layer
2432#endif // SLIC3R_DEBUG
2433 );
2434 // Insert new layer even if there is no interface generated: Likely the support angle is not steep enough to require dense interface,
2435 // however generating a sparse support will be useful for the object stability.
2436 // if (! new_layer->polygons.empty())
2437 contact_out[layer_id * 2] = new_layer;
2438 if (bridging_layer != nullptr) {
2439 bridging_layer->polygons = new_layer->polygons;
2440 bridging_layer->contact_polygons = std::make_unique<Polygons>(*new_layer->contact_polygons);
2441 bridging_layer->overhang_polygons = std::make_unique<Polygons>(*new_layer->overhang_polygons);
2442 if (new_layer->enforcer_polygons)
2443 bridging_layer->enforcer_polygons = std::make_unique<Polygons>(*new_layer->enforcer_polygons);
2444 contact_out[layer_id * 2 + 1] = bridging_layer;
2445 }
2446 }
2447 }
2448 }
2449
2450 // Compress contact_out, remove the nullptr items.
2451 remove_nulls(contact_out);
2452
2453 // Merge close contact layers conservatively: If two layers are closer than the minimum allowed print layer height (the min_layer_height parameter),
2454 // the top contact layer is merged into the bottom contact layer.
2455 merge_contact_layers(m_slicing_params, m_support_params.support_layer_height_min, contact_out);
2456
2457 BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::top_contact_layers() in parallel - end";
2458
2459 return contact_out;
2460}
PointType size() const
Definition BoundingBox.cpp:178
bool has_raft() const
Definition SupportMaterial.hpp:28
static constexpr bool g_config_support_sharp_tails
Definition libslic3r.h:116
Kernel::Point_3 Point
Definition MeshRepair.cpp:81
ClusteredPoints cluster(Index3D &sindex, unsigned max_points, std::function< std::vector< PointIndexEl >(const Index3D &, const PointIndexEl &)> qfn)
Definition Clustering.cpp:27
static const double area_thresh_well_supported
Definition SupportMaterial.cpp:1441
static ExPolygons detect_overhangs(const Layer &layer, const size_t layer_id, Polygons &lower_layer_polygons, const PrintConfig &print_config, const PrintObjectConfig &object_config, SupportAnnotations &annotations, const double gap_xy)
Definition SupportMaterial.cpp:1448
Slic3r::ExPolygons diff_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset)
Definition ClipperUtils.cpp:831
std::vector< ExPolygon > ExPolygons
Definition ExPolygon.hpp:20
static const double length_thresh_well_supported
Definition SupportMaterial.cpp:1440
BoundingBox get_extents(const ExPolygonsWithIds &e)
Definition Emboss.cpp:1374
double area(const ExPolygon &poly)
Definition ExPolygon.hpp:511
bool is_auto(SupportType stype)
Definition PrintConfig.hpp:389
static void merge_contact_layers(const SlicingParameters &slicing_params, double support_layer_height_min, SupportGeneratorLayersPtr &layers)
Definition SupportMaterial.cpp:2071
double nozzle_diameter_for_filament(const PrintConfig &config, int filament_id, bool is_bbl_printer)
Definition PrintConfig.cpp:148
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:1918
Polygons to_polygons(const ExPolygon &src)
Definition ExPolygon.hpp:307
static const double sharp_tail_max_support_height
Definition SupportMaterial.cpp:1444
Slic3r::ExPolygons offset_ex(const Slic3r::Polygons &polygons, const float delta, JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:605
Slic3r::ExPolygons intersection_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset)
Definition ClipperUtils.cpp:878
@ stNormalAuto
Definition PrintConfig.hpp:379
@ stNormal
Definition PrintConfig.hpp:379
void remove_nulls(std::vector< T * > &vec)
Definition libslic3r.h:223
std::string format(const char *fmt, TArgs &&... args)
Definition format.hpp:45
static OverhangCluster * add_overhang(std::vector< OverhangCluster > &clusters, ExPolygon *overhang, int layer_nr, coordf_t offset_scaled)
Definition SupportMaterial.cpp:2166
bool overlaps(const ExPolygons &expolys1, const ExPolygons &expolys2)
Definition ExPolygon.cpp:192
void append(std::vector< T, Alloc > &dest, const std::vector< T, Alloc2 > &src)
Definition libslic3r.h:157
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:1814
static std::tuple< Polygons, Polygons, double > detect_contacts(const Layer &layer, const size_t layer_id, Polygons &overhang_polygons, Polygons &lower_layer_polygons, const PrintConfig &print_config, const PrintObjectConfig &object_config, SupportAnnotations &annotations, SlicesMarginCache &slices_margin, const double gap_xy)
Definition SupportMaterial.cpp:1642

References Slic3r::add_overhang(), Slic3r::append(), Slic3r::area(), Slic3r::area_thresh_well_supported, Slic3r::SupportAnnotations::blockers_layers, buildplate_covered(), Slic3r::Layer::cantilevers, Slic3r::detect_contacts(), Slic3r::detect_overhangs(), Slic3r::diff_ex(), Slic3r::SVG::draw(), Slic3r::empty(), Slic3r::fill_contact_layer(), Slic3r::format(), g_config_support_sharp_tails, Slic3r::get_extents(), has_raft(), has_support(), Slic3r::Layer::height, Slic3r::intersection_ex(), Slic3r::is_auto(), Slic3r::SVG::is_opened(), Slic3r::length_thresh_well_supported, Slic3r::Layer::lower_layer, Slic3r::Layer::lslices, m_object_config, m_print_config, m_slicing_params, m_support_params, Slic3r::BoundingBoxBase< PointType, APointsType >::merge(), Slic3r::merge_contact_layers(), Slic3r::new_contact_layer(), Slic3r::nozzle_diameter_for_filament(), Slic3r::offset_ex(), Slic3r::overlaps(), Slic3r::Layer::print_z, Slic3r::range(), Slic3r::remove_nulls(), scale_, Slic3r::sharp_tail_max_support_height, Slic3r::Layer::sharp_tails, Slic3r::Layer::sharp_tails_height, Slic3r::BoundingBoxBase< PointType, APointsType >::size(), Slic3r::stNormal, Slic3r::stNormalAuto, Slic3r::to_polygons(), and top_contact_layers().

Referenced by generate(), and top_contact_layers().

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
3333{
3334 const float gap_xy_scaled = float(scale_(gap_xy));
3335
3336 // Collect non-empty layers to be processed in parallel.
3337 // This is a good idea as pulling a thread from a thread pool for an empty task is expensive.
3338 SupportGeneratorLayersPtr nonempty_layers;
3339 nonempty_layers.reserve(support_layers.size());
3340 for (size_t idx_layer = 0; idx_layer < support_layers.size(); ++ idx_layer) {
3341 SupportGeneratorLayer *support_layer = support_layers[idx_layer];
3342 if (! support_layer->polygons.empty() && support_layer->print_z >= m_slicing_params.raft_contact_top_z + EPSILON)
3343 // Non-empty support layer and not a raft layer.
3344 nonempty_layers.push_back(support_layer);
3345 }
3346
3347 // For all intermediate support layers:
3348 BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::trim_support_layers_by_object() in parallel - start";
3349 tbb::parallel_for(
3350 tbb::blocked_range<size_t>(0, nonempty_layers.size()),
3351 [this, &object, &nonempty_layers, gap_extra_above, gap_extra_below, gap_xy_scaled](const tbb::blocked_range<size_t>& range) {
3352 size_t idx_object_layer_overlapping = size_t(-1);
3353
3354 auto is_layers_overlap = [](const SupportGeneratorLayer& support_layer, const Layer& object_layer, coordf_t bridging_height = 0.f) -> bool {
3355 if (std::abs(support_layer.print_z - object_layer.print_z) < EPSILON)
3356 return true;
3357
3358 coordf_t object_lh = bridging_height > EPSILON ? bridging_height : object_layer.height;
3359 if (support_layer.print_z < object_layer.print_z && support_layer.print_z > object_layer.print_z - object_lh)
3360 return true;
3361
3362 if (support_layer.print_z > object_layer.print_z && support_layer.bottom_z < object_layer.print_z - EPSILON)
3363 return true;
3364
3365 return false;
3366 };
3367 for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) {
3368 SupportGeneratorLayer &support_layer = *nonempty_layers[idx_layer];
3369 // BOOST_LOG_TRIVIAL(trace) << "Support generator - trim_support_layers_by_object - trimmming non-empty layer " << idx_layer << " of " << nonempty_layers.size();
3370 assert(! support_layer.polygons.empty() && support_layer.print_z >= m_slicing_params.raft_contact_top_z + EPSILON);
3371 // Find the overlapping object layers including the extra above / below gap.
3372 coordf_t z_threshold = support_layer.bottom_print_z() - gap_extra_below + EPSILON;
3373 idx_object_layer_overlapping = Layer::idx_higher_or_equal(
3374 object.layers().begin(), object.layers().end(), idx_object_layer_overlapping,
3375 [z_threshold](const Layer *layer){ return layer->print_z >= z_threshold; });
3376 // Collect all the object layers intersecting with this layer.
3377 Polygons polygons_trimming;
3378 size_t i = idx_object_layer_overlapping;
3379 for (; i < object.layers().size(); ++ i) {
3380 const Layer &object_layer = *object.layers()[i];
3381 if (object_layer.bottom_z() > support_layer.print_z + gap_extra_above - EPSILON)
3382 break;
3383
3384 bool is_overlap = is_layers_overlap(support_layer, object_layer);
3385 for (const ExPolygon& expoly : object_layer.lslices) {
3386 // BBS
3387 bool is_sharptail = !intersection_ex({ expoly }, object_layer.sharp_tails).empty();
3388 coordf_t trimming_offset = is_sharptail ? scale_(sharp_tail_xy_gap) :
3389 is_overlap ? gap_xy_scaled :
3391 polygons_append(polygons_trimming, offset({ expoly }, trimming_offset, SUPPORT_SURFACES_OFFSET_PARAMETERS));
3392 }
3393 }
3394 if (!m_slicing_params.zero_gap_interface_top && m_object_config->thick_bridges) {
3395 // Collect all bottom surfaces, which will be extruded with a bridging flow.
3396 for (; i < object.layers().size(); ++ i) {
3397 const Layer &object_layer = *object.layers()[i];
3398 bool some_region_overlaps = false;
3399 for (LayerRegion *region : object_layer.regions()) {
3400 coordf_t bridging_height = region->region().bridging_height_avg(*m_print_config);
3401 if (object_layer.print_z - bridging_height > support_layer.print_z + gap_extra_above - EPSILON)
3402 break;
3403 some_region_overlaps = true;
3404
3405 bool is_overlap = is_layers_overlap(support_layer, object_layer, bridging_height);
3406 coordf_t trimming_offset = is_overlap ? gap_xy_scaled : scale_(no_overlap_xy_gap);
3407 polygons_append(polygons_trimming,
3408 offset(region->fill_surfaces.filter_by_type(stBottomBridge), trimming_offset, SUPPORT_SURFACES_OFFSET_PARAMETERS));
3409 if (region->region().config().detect_overhang_wall.value)
3410 // Add bridging perimeters.
3411 SupportMaterialInternal::collect_bridging_perimeter_areas(region->perimeters, gap_xy_scaled, polygons_trimming);
3412 }
3413 if (! some_region_overlaps)
3414 break;
3415 }
3416 }
3417
3418 // $layer->slices contains the full shape of layer, thus including
3419 // perimeter's width. $support contains the full shape of support
3420 // material, thus including the width of its foremost extrusion.
3421 // We leave a gap equal to a full extrusion width.
3422 support_layer.polygons = diff(support_layer.polygons, polygons_trimming);
3423 }
3424 });
3425 BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::trim_support_layers_by_object() in parallel - end";
3426}
#define SUPPORT_SURFACES_OFFSET_PARAMETERS
Definition PrintObject.cpp:5148
static void collect_bridging_perimeter_areas(const ExtrusionLoop &loop, const float expansion_scaled, Polygons &out)
Definition SupportMaterial.cpp:1251
static const double no_overlap_xy_gap
Definition SupportMaterial.cpp:1443
static const double sharp_tail_xy_gap
Definition SupportMaterial.cpp:1442
@ stBottomBridge
Definition Surface.hpp:22
Slic3r::Polygons diff(const Slic3r::Polygon &subject, const Slic3r::Polygon &clip, ApplySafetyOffset do_safety_offset)
Definition ClipperUtils.cpp:731

References Slic3r::Layer::bottom_z(), Slic3r::SupportMaterialInternal::collect_bridging_perimeter_areas(), Slic3r::diff(), Slic3r::empty(), EPSILON, Slic3r::intersection_ex(), Slic3r::Layer::lslices, m_object_config, m_print_config, m_slicing_params, Slic3r::no_overlap_xy_gap, Slic3r::offset(), Slic3r::SupportGeneratorLayer::polygons, Slic3r::polygons_append(), Slic3r::Layer::print_z, Slic3r::SupportGeneratorLayer::print_z, Slic3r::range(), Slic3r::Layer::regions(), scale_, Slic3r::sharp_tail_xy_gap, Slic3r::Layer::sharp_tails, Slic3r::stBottomBridge, SUPPORT_SURFACES_OFFSET_PARAMETERS, and trim_support_layers_by_object().

Referenced by bottom_contact_layers_and_layer_support_areas(), generate(), and trim_support_layers_by_object().

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
2933{
2934 tbb::parallel_for(tbb::blocked_range<int>(0, int(top_contacts.size())),
2935 [&bottom_contacts, &top_contacts](const tbb::blocked_range<int>& range) {
2936 int idx_bottom_overlapping_first = -2;
2937 // For all top contact layers, counting downwards due to the way idx_higher_or_equal caches the last index to avoid repeated binary search.
2938 for (int idx_top = range.end() - 1; idx_top >= range.begin(); -- idx_top) {
2939 SupportGeneratorLayer &layer_top = *top_contacts[idx_top];
2940 // Find the first bottom layer overlapping with layer_top.
2941 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; });
2942 // For all top contact layers overlapping with the thick bottom contact layer:
2943 for (int idx_bottom_overlapping = idx_bottom_overlapping_first; idx_bottom_overlapping >= 0; -- idx_bottom_overlapping) {
2944 const SupportGeneratorLayer &layer_bottom = *bottom_contacts[idx_bottom_overlapping];
2945 assert(layer_bottom.bottom_print_z() - EPSILON <= layer_top.bottom_z);
2946 if (layer_top.print_z < layer_bottom.print_z + EPSILON) {
2947 // Layers overlap. Trim layer_top with layer_bottom.
2948 layer_top.polygons = diff(layer_top.polygons, layer_bottom.polygons);
2949 } else
2950 break;
2951 }
2952 }
2953 });
2954}

References Slic3r::range(), and trim_top_contacts_by_bottom_contacts().

Referenced by generate(), and trim_top_contacts_by_bottom_contacts().

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

Member Data Documentation

◆ m_object_config

◆ m_print_config

const PrintConfig* Slic3r::PrintObjectSupportMaterial::m_print_config
private

◆ m_slicing_params

◆ m_support_params


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