Prusa Slicer 2.6.0
Loading...
Searching...
No Matches
Slic3r::FFFSupport Namespace Reference

Classes

struct  LoopInterfaceProcessor
 
class  SupportGeneratorLayer
 
struct  SupportGeneratorLayerExtruded
 
class  SupportGeneratorLayerStorage
 
struct  SupportParameters
 

Typedefs

typedef std::vector< SupportGeneratorLayerExtruded * > SupportGeneratorLayerExtrudedPtrs
 
using SupportGeneratorLayersPtr = std::vector< SupportGeneratorLayer * >
 

Enumerations

enum class  SupporLayerType {
  Unknown = 0 , RaftBase , RaftInterface , BottomContact ,
  BottomInterface , Base , TopInterface , TopContact ,
  Intermediate
}
 

Functions

void remove_bridges_from_contacts (const PrintConfig &print_config, const Layer &lower_layer, const LayerRegion &layerm, float fw, Polygons &contact_polygons)
 
std::pair< SupportGeneratorLayersPtr, SupportGeneratorLayersPtrgenerate_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)
 
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)
 
static void fill_expolygon_generate_paths (ExtrusionEntitiesPtr &dst, ExPolygon &&expolygon, Fill *filler, const FillParams &fill_params, float density, ExtrusionRole role, const Flow &flow)
 
static void fill_expolygons_generate_paths (ExtrusionEntitiesPtr &dst, ExPolygons &&expolygons, Fill *filler, const FillParams &fill_params, float density, ExtrusionRole role, const Flow &flow)
 
static void fill_expolygons_generate_paths (ExtrusionEntitiesPtr &dst, ExPolygons &&expolygons, Fill *filler, float density, ExtrusionRole role, const Flow &flow)
 
static Polylines draw_perimeters (const ExPolygon &expoly, double clip_length)
 
static void tree_supports_generate_paths (ExtrusionEntitiesPtr &dst, const Polygons &polygons, const Flow &flow, const SupportParameters &support_params)
 
static void fill_expolygons_with_sheath_generate_paths (ExtrusionEntitiesPtr &dst, const Polygons &polygons, Fill *filler, float density, ExtrusionRole role, const Flow &flow, bool with_sheath, bool no_sort)
 
static void modulate_extrusion_by_overlapping_layers (ExtrusionEntitiesPtr &extrusions_in_out, const SupportGeneratorLayer &this_layer, const SupportGeneratorLayersPtr &overlapping_layers)
 
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)
 
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)
 
template<typename IteratorType , typename IndexType , typename FN_HIGHER_EQUAL >
IndexType idx_higher_or_equal (IteratorType begin, IteratorType end, IndexType idx, FN_HIGHER_EQUAL fn_higher_equal)
 
template<typename T , typename IndexType , typename FN_HIGHER_EQUAL >
IndexType idx_higher_or_equal (const std::vector< T > &vec, IndexType idx, FN_HIGHER_EQUAL fn_higher_equal)
 
template<typename IT , typename FN_LOWER_EQUAL >
int idx_lower_or_equal (IT begin, IT end, int idx, FN_LOWER_EQUAL fn_lower_equal)
 
template<typename T , typename FN_LOWER_EQUAL >
int idx_lower_or_equal (const std::vector< T * > &vec, int idx, FN_LOWER_EQUAL fn_lower_equal)
 
const char * support_surface_type_to_color_name (const SupporLayerType surface_type)
 
Point export_support_surface_type_legend_to_svg_box_size ()
 
void export_support_surface_type_legend_to_svg (SVG &svg, const Point &pos)
 
void export_print_z_polygons_to_svg (const char *path, SupportGeneratorLayer **const layers, int n_layers)
 
void export_print_z_polygons_and_extrusions_to_svg (const char *path, SupportGeneratorLayer **const layers, int n_layers, SupportLayer &support_layer)
 
void export_print_z_polygons_to_svg (const char *path, SupportGeneratorLayer **const layers, size_t n_layers)
 
void export_print_z_polygons_and_extrusions_to_svg (const char *path, SupportGeneratorLayer **const layers, size_t n_layers, SupportLayer &support_layer)
 

Variables

static constexpr const std::initializer_list< SupporLayerTypesupport_types_interface
 

Typedef Documentation

◆ SupportGeneratorLayerExtrudedPtrs

◆ SupportGeneratorLayersPtr

Enumeration Type Documentation

◆ SupporLayerType

Enumerator
Unknown 
RaftBase 
RaftInterface 
BottomContact 
BottomInterface 
Base 
TopInterface 
TopContact 
Intermediate 
15 {
16 Unknown = 0,
17 // Ratft base layer, to be printed with the support material.
19 // Raft interface layer, to be printed with the support interface material.
21 // Bottom contact layer placed over a top surface of an object. To be printed with a support interface material.
23 // Dense interface layer, to be printed with the support interface material.
24 // This layer is separated from an object by an BottomContact layer.
26 // Sparse base support layer, to be printed with a support material.
27 Base,
28 // Dense interface layer, to be printed with the support interface material.
29 // This layer is separated from an object with TopContact layer.
31 // Top contact layer directly supporting an overhang. To be printed with a support interface material.
33 // Some undecided type yet. It will turn into Base first, then it may turn into BottomInterface or TopInterface.
35};

Function Documentation

◆ draw_perimeters()

static Polylines Slic3r::FFFSupport::draw_perimeters ( const ExPolygon expoly,
double  clip_length 
)
static
520{
521 // Draw the perimeters.
522 Polylines polylines;
523 polylines.reserve(expoly.holes.size() + 1);
524 for (size_t i = 0; i <= expoly.holes.size(); ++ i) {
525 Polyline pl(i == 0 ? expoly.contour.points : expoly.holes[i - 1].points);
526 pl.points.emplace_back(pl.points.front());
527 if (i > 0)
528 // It is a hole, reverse it.
529 pl.reverse();
530 // so that all contours are CCW oriented.
531 pl.clip_end(clip_length);
532 polylines.emplace_back(std::move(pl));
533 }
534 return polylines;
535}
Polygon contour
Definition ExPolygon.hpp:35
Polygons holes
Definition ExPolygon.hpp:36
Points points
Definition MultiPoint.hpp:18
Definition Polyline.hpp:17
std::vector< Polyline > Polylines
Definition Polyline.hpp:14

References Slic3r::ExPolygon::contour, draw_perimeters(), Slic3r::ExPolygon::holes, and Slic3r::MultiPoint::points.

Referenced by draw_perimeters(), fill_expolygons_with_sheath_generate_paths(), and tree_supports_generate_paths().

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

◆ export_print_z_polygons_and_extrusions_to_svg() [1/2]

void Slic3r::FFFSupport::export_print_z_polygons_and_extrusions_to_svg ( const char *  path,
SupportGeneratorLayer **const  layers,
int  n_layers,
SupportLayer support_layer 
)
82{
83 BoundingBox bbox;
84 for (int i = 0; i < n_layers; ++ i)
85 bbox.merge(get_extents(layers[i]->polygons));
87 Point legend_pos(bbox.min(0), bbox.max(1));
88 bbox.merge(Point(std::max(bbox.min(0) + legend_size(0), bbox.max(0)), bbox.max(1) + legend_size(1)));
89 SVG svg(path, bbox);
90 const float transparency = 0.5f;
91 for (int i = 0; i < n_layers; ++ i)
92 svg.draw(union_ex(layers[i]->polygons), support_surface_type_to_color_name(layers[i]->layer_type), transparency);
93 for (int i = 0; i < n_layers; ++ i)
94 svg.draw(to_polylines(layers[i]->polygons), support_surface_type_to_color_name(layers[i]->layer_type));
95
96 Polygons polygons_support, polygons_interface;
97 support_layer.support_fills.polygons_covered_by_width(polygons_support, float(SCALED_EPSILON));
98// support_layer.support_interface_fills.polygons_covered_by_width(polygons_interface, SCALED_EPSILON);
99 svg.draw(union_ex(polygons_support), "brown");
100 svg.draw(union_ex(polygons_interface), "black");
101
103 svg.Close();
104}
PointType max
Definition BoundingBox.hpp:17
void merge(const PointType &point)
Definition BoundingBox.cpp:62
PointType min
Definition BoundingBox.hpp:16
Definition BoundingBox.hpp:181
void polygons_covered_by_width(Polygons &out, const float scaled_epsilon) const override
Definition ExtrusionEntityCollection.cpp:98
Definition Point.hpp:158
Definition SVG.hpp:14
ExtrusionEntityCollection support_fills
Definition Layer.hpp:436
#define SCALED_EPSILON
Definition libslic3r.h:71
const char * support_surface_type_to_color_name(const SupporLayerType surface_type)
Definition SupportDebug.cpp:11
void export_support_surface_type_legend_to_svg(SVG &svg, const Point &pos)
Definition SupportDebug.cpp:31
Point export_support_surface_type_legend_to_svg_box_size()
Definition SupportDebug.cpp:26
std::vector< Polygon, PointsAllocator< Polygon > > Polygons
Definition Polygon.hpp:15
Polylines to_polylines(const ExPolygon &src)
Definition ExPolygon.hpp:209
Slic3r::ExPolygons union_ex(const Slic3r::Polygons &subject, ClipperLib::PolyFillType fill_type)
Definition ClipperUtils.cpp:774
BoundingBox get_extents(const ExPolygon &expolygon)
Definition ExPolygon.cpp:352
Kernel::Point_2 Point
Definition point_areas.cpp:20

References Slic3r::SVG::Close(), Slic3r::SVG::draw(), export_support_surface_type_legend_to_svg(), export_support_surface_type_legend_to_svg_box_size(), Slic3r::get_extents(), Slic3r::BoundingBoxBase< PointType, APointsType >::max, Slic3r::BoundingBoxBase< PointType, APointsType >::merge(), Slic3r::BoundingBoxBase< PointType, APointsType >::min, Slic3r::ExtrusionEntityCollection::polygons_covered_by_width(), SCALED_EPSILON, Slic3r::SupportLayer::support_fills, support_surface_type_to_color_name(), Slic3r::to_polylines(), and Slic3r::union_ex().

Referenced by Slic3r::PrintObjectSupportMaterial::generate(), and Slic3r::FFFTreeSupport::generate_support_areas().

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

◆ export_print_z_polygons_and_extrusions_to_svg() [2/2]

void Slic3r::FFFSupport::export_print_z_polygons_and_extrusions_to_svg ( const char *  path,
SupportGeneratorLayer **const  layers,
size_t  n_layers,
SupportLayer support_layer 
)

◆ export_print_z_polygons_to_svg() [1/2]

void Slic3r::FFFSupport::export_print_z_polygons_to_svg ( const char *  path,
SupportGeneratorLayer **const  layers,
int  n_layers 
)
60{
61 BoundingBox bbox;
62 for (int i = 0; i < n_layers; ++ i)
63 bbox.merge(get_extents(layers[i]->polygons));
65 Point legend_pos(bbox.min(0), bbox.max(1));
66 bbox.merge(Point(std::max(bbox.min(0) + legend_size(0), bbox.max(0)), bbox.max(1) + legend_size(1)));
67 SVG svg(path, bbox);
68 const float transparency = 0.5f;
69 for (int i = 0; i < n_layers; ++ i)
70 svg.draw(union_ex(layers[i]->polygons), support_surface_type_to_color_name(layers[i]->layer_type), transparency);
71 for (int i = 0; i < n_layers; ++ i)
72 svg.draw(to_polylines(layers[i]->polygons), support_surface_type_to_color_name(layers[i]->layer_type));
74 svg.Close();
75}

References Slic3r::SVG::Close(), Slic3r::SVG::draw(), export_support_surface_type_legend_to_svg(), export_support_surface_type_legend_to_svg_box_size(), Slic3r::get_extents(), Slic3r::BoundingBoxBase< PointType, APointsType >::max, Slic3r::BoundingBoxBase< PointType, APointsType >::merge(), Slic3r::BoundingBoxBase< PointType, APointsType >::min, support_surface_type_to_color_name(), Slic3r::to_polylines(), and Slic3r::union_ex().

Referenced by Slic3r::PrintObjectSupportMaterial::generate(), and Slic3r::FFFTreeSupport::generate_support_areas().

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

◆ export_print_z_polygons_to_svg() [2/2]

void Slic3r::FFFSupport::export_print_z_polygons_to_svg ( const char *  path,
SupportGeneratorLayer **const  layers,
size_t  n_layers 
)

◆ export_support_surface_type_legend_to_svg()

void Slic3r::FFFSupport::export_support_surface_type_legend_to_svg ( SVG svg,
const Point pos 
)
32{
33 // 1st row
34 coord_t pos_x0 = pos(0) + scale_(1.);
35 coord_t pos_x = pos_x0;
36 coord_t pos_y = pos(1) + scale_(1.5);
37 coord_t step_x = scale_(10.);
38 svg.draw_legend(Point(pos_x, pos_y), "top contact" , support_surface_type_to_color_name(SupporLayerType::TopContact));
39 pos_x += step_x;
40 svg.draw_legend(Point(pos_x, pos_y), "top iface" , support_surface_type_to_color_name(SupporLayerType::TopInterface));
41 pos_x += step_x;
42 svg.draw_legend(Point(pos_x, pos_y), "base" , support_surface_type_to_color_name(SupporLayerType::Base));
43 pos_x += step_x;
44 svg.draw_legend(Point(pos_x, pos_y), "bottom iface" , support_surface_type_to_color_name(SupporLayerType::BottomInterface));
45 pos_x += step_x;
46 svg.draw_legend(Point(pos_x, pos_y), "bottom contact" , support_surface_type_to_color_name(SupporLayerType::BottomContact));
47 // 2nd row
48 pos_x = pos_x0;
49 pos_y = pos(1)+scale_(2.8);
50 svg.draw_legend(Point(pos_x, pos_y), "raft interface" , support_surface_type_to_color_name(SupporLayerType::RaftInterface));
51 pos_x += step_x;
52 svg.draw_legend(Point(pos_x, pos_y), "raft base" , support_surface_type_to_color_name(SupporLayerType::RaftBase));
53 pos_x += step_x;
54 svg.draw_legend(Point(pos_x, pos_y), "unknown" , support_surface_type_to_color_name(SupporLayerType::Unknown));
55 pos_x += step_x;
56 svg.draw_legend(Point(pos_x, pos_y), "intermediate" , support_surface_type_to_color_name(SupporLayerType::Intermediate));
57}
void draw_legend(const Point &pt, const char *text, const char *color, coordf_t font_size=10.f)
Definition SVG.cpp:285
#define scale_(val)
Definition libslic3r.h:69
int32_t coord_t
Definition libslic3r.h:39

References Base, BottomContact, BottomInterface, Slic3r::SVG::draw_legend(), Intermediate, RaftBase, RaftInterface, scale_, support_surface_type_to_color_name(), TopContact, TopInterface, and Unknown.

Referenced by export_print_z_polygons_and_extrusions_to_svg(), and export_print_z_polygons_to_svg().

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

◆ export_support_surface_type_legend_to_svg_box_size()

Point Slic3r::FFFSupport::export_support_surface_type_legend_to_svg_box_size ( )
27{
28 return Point(scale_(1.+10.*8.), scale_(3.));
29}

References scale_.

Referenced by export_print_z_polygons_and_extrusions_to_svg(), and export_print_z_polygons_to_svg().

+ Here is the caller graph for this function:

◆ fill_expolygon_generate_paths()

static void Slic3r::FFFSupport::fill_expolygon_generate_paths ( ExtrusionEntitiesPtr dst,
ExPolygon &&  expolygon,
Fill filler,
const FillParams fill_params,
float  density,
ExtrusionRole  role,
const Flow flow 
)
inlinestatic
477{
478 Surface surface(stInternal, std::move(expolygon));
479 Polylines polylines;
480 try {
481 assert(!fill_params.use_arachne);
482 polylines = filler->fill_surface(&surface, fill_params);
483 } catch (InfillFailedException &) {
484 }
485 extrusion_entities_append_paths(
486 dst,
487 std::move(polylines),
488 role,
489 flow.mm3_per_mm(), flow.width(), flow.height());
490}
virtual Polylines fill_surface(const Surface *surface, const FillParams &params)
Definition FillBase.cpp:84
float height() const
Definition Flow.hpp:64
float width() const
Definition Flow.hpp:60
double mm3_per_mm() const
Definition Flow.cpp:205
Definition FillBase.hpp:29
Definition Surface.hpp:32
bool use_arachne
Definition FillBase.hpp:63

References Slic3r::extrusion_entities_append_paths(), fill_expolygon_generate_paths(), Slic3r::Fill::fill_surface(), Slic3r::Flow::height(), Slic3r::Flow::mm3_per_mm(), Slic3r::stInternal, Slic3r::FillParams::use_arachne, and Slic3r::Flow::width().

Referenced by fill_expolygon_generate_paths(), and fill_expolygons_generate_paths().

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

◆ fill_expolygons_generate_paths() [1/2]

static void Slic3r::FFFSupport::fill_expolygons_generate_paths ( ExtrusionEntitiesPtr dst,
ExPolygons &&  expolygons,
Fill filler,
const FillParams fill_params,
float  density,
ExtrusionRole  role,
const Flow flow 
)
inlinestatic
500{
501 for (ExPolygon &expoly : expolygons)
502 fill_expolygon_generate_paths(dst, std::move(expoly), filler, fill_params, density, role, flow);
503}
Definition ExPolygon.hpp:16
static void fill_expolygon_generate_paths(ExtrusionEntitiesPtr &dst, ExPolygon &&expolygon, Fill *filler, const FillParams &fill_params, float density, ExtrusionRole role, const Flow &flow)
Definition SupportCommon.cpp:469
STL namespace.

References fill_expolygon_generate_paths(), and fill_expolygons_generate_paths().

Referenced by fill_expolygons_generate_paths(), fill_expolygons_generate_paths(), and fill_expolygons_with_sheath_generate_paths().

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

◆ fill_expolygons_generate_paths() [2/2]

static void Slic3r::FFFSupport::fill_expolygons_generate_paths ( ExtrusionEntitiesPtr dst,
ExPolygons &&  expolygons,
Fill filler,
float  density,
ExtrusionRole  role,
const Flow flow 
)
inlinestatic
512{
513 FillParams fill_params;
514 fill_params.density = density;
515 fill_params.dont_adjust = true;
516 fill_expolygons_generate_paths(dst, std::move(expolygons), filler, fill_params, density, role, flow);
517}
static void fill_expolygons_generate_paths(ExtrusionEntitiesPtr &dst, ExPolygons &&expolygons, Fill *filler, const FillParams &fill_params, float density, ExtrusionRole role, const Flow &flow)
Definition SupportCommon.cpp:492
Definition FillBase.hpp:35
bool dont_adjust
Definition FillBase.hpp:52
float density
Definition FillBase.hpp:41

References Slic3r::FillParams::density, Slic3r::FillParams::dont_adjust, and fill_expolygons_generate_paths().

+ Here is the call graph for this function:

◆ fill_expolygons_with_sheath_generate_paths()

static void Slic3r::FFFSupport::fill_expolygons_with_sheath_generate_paths ( ExtrusionEntitiesPtr dst,
const Polygons polygons,
Fill filler,
float  density,
ExtrusionRole  role,
const Flow flow,
bool  with_sheath,
bool  no_sort 
)
inlinestatic
772{
773 if (polygons.empty())
774 return;
775
776 if (! with_sheath) {
777 fill_expolygons_generate_paths(dst, closing_ex(polygons, float(SCALED_EPSILON)), filler, density, role, flow);
778 return;
779 }
780
781 FillParams fill_params;
782 fill_params.density = density;
783 fill_params.dont_adjust = true;
784
785 const double spacing = flow.scaled_spacing();
786 // Clip the sheath path to avoid the extruder to get exactly on the first point of the loop.
787 const double clip_length = spacing * 0.15;
788
789 for (ExPolygon &expoly : closing_ex(polygons, float(SCALED_EPSILON), float(SCALED_EPSILON + 0.5*flow.scaled_width()))) {
790 // Don't reorder the skirt and its infills.
791 std::unique_ptr<ExtrusionEntityCollection> eec;
792 if (no_sort) {
793 eec = std::make_unique<ExtrusionEntityCollection>();
794 eec->no_sort = true;
795 }
796 ExtrusionEntitiesPtr &out = no_sort ? eec->entities : dst;
797 extrusion_entities_append_paths(out, draw_perimeters(expoly, clip_length), ExtrusionRole::SupportMaterial, flow.mm3_per_mm(), flow.width(), flow.height());
798 // Fill in the rest.
799 fill_expolygons_generate_paths(out, offset_ex(expoly, float(-0.4 * spacing)), filler, fill_params, density, role, flow);
800 if (no_sort && ! eec->empty())
801 dst.emplace_back(eec.release());
802 }
803}
coord_t scaled_spacing() const
Definition Flow.hpp:67
Slic3r::ExPolygons closing_ex(const Slic3r::Polygons &polygons, const float delta1, const float delta2, ClipperLib::JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:593

References Slic3r::closing_ex(), Slic3r::FillParams::density, Slic3r::FillParams::dont_adjust, draw_perimeters(), Slic3r::extrusion_entities_append_paths(), fill_expolygons_generate_paths(), fill_expolygons_with_sheath_generate_paths(), Slic3r::Flow::height(), Slic3r::Flow::mm3_per_mm(), Slic3r::offset_ex(), SCALED_EPSILON, Slic3r::Flow::scaled_spacing(), Slic3r::Flow::scaled_width(), and Slic3r::Flow::width().

Referenced by fill_expolygons_with_sheath_generate_paths(), and generate_support_toolpaths().

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

◆ generate_interface_layers()

std::pair< SupportGeneratorLayersPtr, SupportGeneratorLayersPtr > Slic3r::FFFSupport::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 
)
135{
136 std::pair<SupportGeneratorLayersPtr, SupportGeneratorLayersPtr> base_and_interface_layers;
137
138 if (! intermediate_layers.empty() && support_params.has_interfaces()) {
139 // For all intermediate layers, collect top contact surfaces, which are not further than support_material_interface_layers.
140 BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::generate_interface_layers() in parallel - start";
141 const bool snug_supports = config.support_material_style.value == smsSnug;
142 const bool smooth_supports = config.support_material_style.value != smsGrid;
143 SupportGeneratorLayersPtr &interface_layers = base_and_interface_layers.first;
144 SupportGeneratorLayersPtr &base_interface_layers = base_and_interface_layers.second;
145 interface_layers.assign(intermediate_layers.size(), nullptr);
146 if (support_params.has_base_interfaces())
147 base_interface_layers.assign(intermediate_layers.size(), nullptr);
148 const auto smoothing_distance = support_params.support_material_interface_flow.scaled_spacing() * 1.5;
149 const auto minimum_island_radius = support_params.support_material_interface_flow.scaled_spacing() / support_params.interface_density;
150 const auto closing_distance = smoothing_distance; // scaled<float>(config.support_material_closing_radius.value);
151 // Insert a new layer into base_interface_layers, if intersection with base exists.
152 auto insert_layer = [&layer_storage, smooth_supports, closing_distance, smoothing_distance, minimum_island_radius](
153 SupportGeneratorLayer &intermediate_layer, Polygons &bottom, Polygons &&top, SupportGeneratorLayer *top_interface_layer,
154 const Polygons *subtract, SupporLayerType type) -> SupportGeneratorLayer* {
155 bool has_top_interface = top_interface_layer && ! top_interface_layer->polygons.empty();
156 assert(! bottom.empty() || ! top.empty() || has_top_interface);
157 // Merge top into bottom, unite them with a safety offset.
158 append(bottom, std::move(top));
159 // Merge top / bottom interfaces. For snug supports, merge using closing distance and regularize (close concave corners).
160 bottom = intersection(
161 smooth_supports ?
162 smooth_outward(closing(std::move(bottom), closing_distance + minimum_island_radius, closing_distance, SUPPORT_SURFACES_OFFSET_PARAMETERS), smoothing_distance) :
163 union_safety_offset(std::move(bottom)),
164 intermediate_layer.polygons);
165 if (has_top_interface) {
166 // Don't trim the precomputed Organic supports top interface with base layer
167 // as the precomputed top interface likely expands over multiple tree tips.
168 bottom = union_(std::move(top_interface_layer->polygons), bottom);
169 top_interface_layer->polygons.clear();
170 }
171 if (! bottom.empty()) {
172 //FIXME Remove non-printable tiny islands, let them be printed using the base support.
173 //bottom = opening(std::move(bottom), minimum_island_radius);
174 if (! bottom.empty()) {
175 SupportGeneratorLayer &layer_new = top_interface_layer ? *top_interface_layer : layer_storage.allocate(type);
176 layer_new.polygons = std::move(bottom);
177 layer_new.print_z = intermediate_layer.print_z;
178 layer_new.bottom_z = intermediate_layer.bottom_z;
179 layer_new.height = intermediate_layer.height;
180 layer_new.bridging = intermediate_layer.bridging;
181 // Subtract the interface from the base regions.
182 intermediate_layer.polygons = diff(intermediate_layer.polygons, layer_new.polygons);
183 if (subtract)
184 // Trim the base interface layer with the interface layer.
185 layer_new.polygons = diff(std::move(layer_new.polygons), *subtract);
186 //FIXME filter layer_new.polygons islands by a minimum area?
187 // $interface_area = [ grep abs($_->area) >= $area_threshold, @$interface_area ];
188 return &layer_new;
189 }
190 }
191 return nullptr;
192 };
193 tbb::parallel_for(tbb::blocked_range<int>(0, int(intermediate_layers.size())),
194 [&bottom_contacts, &top_contacts, &top_interface_layers, &top_base_interface_layers, &intermediate_layers, &insert_layer, &support_params,
195 snug_supports, &interface_layers, &base_interface_layers](const tbb::blocked_range<int>& range) {
196 // Gather the top / bottom contact layers intersecting with num_interface_layers resp. num_interface_layers_only intermediate layers above / below
197 // this intermediate layer.
198 // Index of the first top contact layer intersecting the current intermediate layer.
199 auto idx_top_contact_first = -1;
200 // Index of the first bottom contact layer intersecting the current intermediate layer.
201 auto idx_bottom_contact_first = -1;
202 // Index of the first top interface layer intersecting the current intermediate layer.
203 auto idx_top_interface_first = -1;
204 // Index of the first top contact interface layer intersecting the current intermediate layer.
205 auto idx_top_base_interface_first = -1;
206 auto num_intermediate = int(intermediate_layers.size());
207 for (int idx_intermediate_layer = range.begin(); idx_intermediate_layer < range.end(); ++ idx_intermediate_layer) {
208 SupportGeneratorLayer &intermediate_layer = *intermediate_layers[idx_intermediate_layer];
209 Polygons polygons_top_contact_projected_interface;
210 Polygons polygons_top_contact_projected_base;
211 Polygons polygons_bottom_contact_projected_interface;
212 Polygons polygons_bottom_contact_projected_base;
213 if (support_params.num_top_interface_layers > 0) {
214 // Top Z coordinate of a slab, over which we are collecting the top / bottom contact surfaces
215 coordf_t top_z = intermediate_layers[std::min(num_intermediate - 1, idx_intermediate_layer + int(support_params.num_top_interface_layers) - 1)]->print_z;
216 coordf_t top_inteface_z = std::numeric_limits<coordf_t>::max();
217 if (support_params.num_top_base_interface_layers > 0)
218 // Some top base interface layers will be generated.
219 top_inteface_z = support_params.num_top_interface_layers_only() == 0 ?
220 // Only base interface layers to generate.
221 - std::numeric_limits<coordf_t>::max() :
222 intermediate_layers[std::min(num_intermediate - 1, idx_intermediate_layer + int(support_params.num_top_interface_layers_only()) - 1)]->print_z;
223 // Move idx_top_contact_first up until above the current print_z.
224 idx_top_contact_first = idx_higher_or_equal(top_contacts, idx_top_contact_first, [&intermediate_layer](const SupportGeneratorLayer *layer){ return layer->print_z >= intermediate_layer.print_z; }); // - EPSILON
225 // Collect the top contact areas above this intermediate layer, below top_z.
226 for (int idx_top_contact = idx_top_contact_first; idx_top_contact < int(top_contacts.size()); ++ idx_top_contact) {
227 const SupportGeneratorLayer &top_contact_layer = *top_contacts[idx_top_contact];
228 //FIXME maybe this adds one interface layer in excess?
229 if (top_contact_layer.bottom_z - EPSILON > top_z)
230 break;
231 polygons_append(top_contact_layer.bottom_z - EPSILON > top_inteface_z ? polygons_top_contact_projected_base : polygons_top_contact_projected_interface,
232 // For snug supports, project the overhang polygons covering the whole overhang, so that they will merge without a gap with support polygons of the other layers.
233 // For grid supports, merging of support regions will be performed by the projection into grid.
234 snug_supports ? *top_contact_layer.overhang_polygons : top_contact_layer.polygons);
235 }
236 }
237 if (support_params.num_bottom_interface_layers > 0) {
238 // Bottom Z coordinate of a slab, over which we are collecting the top / bottom contact surfaces
239 coordf_t bottom_z = intermediate_layers[std::max(0, idx_intermediate_layer - int(support_params.num_bottom_interface_layers) + 1)]->bottom_z;
240 coordf_t bottom_interface_z = - std::numeric_limits<coordf_t>::max();
241 if (support_params.num_bottom_base_interface_layers > 0)
242 // Some bottom base interface layers will be generated.
243 bottom_interface_z = support_params.num_bottom_interface_layers_only() == 0 ?
244 // Only base interface layers to generate.
245 std::numeric_limits<coordf_t>::max() :
246 intermediate_layers[std::max(0, idx_intermediate_layer - int(support_params.num_bottom_interface_layers_only()))]->bottom_z;
247 // Move idx_bottom_contact_first up until touching bottom_z.
248 idx_bottom_contact_first = idx_higher_or_equal(bottom_contacts, idx_bottom_contact_first, [bottom_z](const SupportGeneratorLayer *layer){ return layer->print_z >= bottom_z - EPSILON; });
249 // Collect the top contact areas above this intermediate layer, below top_z.
250 for (int idx_bottom_contact = idx_bottom_contact_first; idx_bottom_contact < int(bottom_contacts.size()); ++ idx_bottom_contact) {
251 const SupportGeneratorLayer &bottom_contact_layer = *bottom_contacts[idx_bottom_contact];
252 if (bottom_contact_layer.print_z - EPSILON > intermediate_layer.bottom_z)
253 break;
254 polygons_append(bottom_contact_layer.print_z - EPSILON > bottom_interface_z ? polygons_bottom_contact_projected_interface : polygons_bottom_contact_projected_base, bottom_contact_layer.polygons);
255 }
256 }
257 auto resolve_same_layer = [](SupportGeneratorLayersPtr &layers, int &idx, coordf_t print_z) -> SupportGeneratorLayer* {
258 if (! layers.empty()) {
259 idx = idx_higher_or_equal(layers, idx, [print_z](const SupportGeneratorLayer *layer) { return layer->print_z > print_z - EPSILON; });
260 if (idx < int(layers.size()) && layers[idx]->print_z < print_z + EPSILON)
261 return layers[idx];
262 }
263 return nullptr;
264 };
265 SupportGeneratorLayer *top_interface_layer = resolve_same_layer(top_interface_layers, idx_top_interface_first, intermediate_layer.print_z);
266 SupportGeneratorLayer *top_base_interface_layer = resolve_same_layer(top_base_interface_layers, idx_top_base_interface_first, intermediate_layer.print_z);
267 SupportGeneratorLayer *interface_layer = nullptr;
268 if (! polygons_bottom_contact_projected_interface.empty() || ! polygons_top_contact_projected_interface.empty() ||
269 (top_interface_layer && ! top_interface_layer->polygons.empty())) {
270 interface_layer = insert_layer(
271 intermediate_layer, polygons_bottom_contact_projected_interface, std::move(polygons_top_contact_projected_interface), top_interface_layer,
272 nullptr, polygons_top_contact_projected_interface.empty() ? SupporLayerType::BottomInterface : SupporLayerType::TopInterface);
273 interface_layers[idx_intermediate_layer] = interface_layer;
274 }
275 if (! polygons_bottom_contact_projected_base.empty() || ! polygons_top_contact_projected_base.empty() ||
276 (top_base_interface_layer && ! top_base_interface_layer->polygons.empty()))
277 base_interface_layers[idx_intermediate_layer] = insert_layer(
278 intermediate_layer, polygons_bottom_contact_projected_base, std::move(polygons_top_contact_projected_base), top_base_interface_layer,
279 interface_layer ? &interface_layer->polygons : nullptr, SupporLayerType::Base);
280 }
281 });
282
283 // Compress contact_out, remove the nullptr items.
284 // The parallel_for above may not have merged all the interface and base_interface layers
285 // generated by the Organic supports code, do it here.
286 auto merge_remove_empty = [](SupportGeneratorLayersPtr &in1, SupportGeneratorLayersPtr &in2) {
287 auto remove_empty = [](SupportGeneratorLayersPtr &vec) {
288 vec.erase(
289 std::remove_if(vec.begin(), vec.end(), [](const SupportGeneratorLayer *ptr) { return ptr == nullptr || ptr->polygons.empty(); }),
290 vec.end());
291 };
292 remove_empty(in1);
293 remove_empty(in2);
294 if (in2.empty())
295 return std::move(in1);
296 else if (in1.empty())
297 return std::move(in2);
298 else {
299 SupportGeneratorLayersPtr out(in1.size() + in2.size(), nullptr);
300 std::merge(in1.begin(), in1.end(), in2.begin(), in2.end(), out.begin(), [](auto* l, auto* r) { return l->print_z < r->print_z; });
301 return out;
302 }
303 };
304 interface_layers = merge_remove_empty(interface_layers, top_interface_layers);
305 base_interface_layers = merge_remove_empty(base_interface_layers, top_base_interface_layers);
306 BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::generate_interface_layers() in parallel - end";
307 }
308
309 return base_and_interface_layers;
310}
#define SUPPORT_SURFACES_OFFSET_PARAMETERS
Definition SupportCommon.cpp:41
Definition SupportLayer.hpp:41
Polygons polygons
Definition SupportLayer.hpp:107
SupportGeneratorLayer & allocate(SupporLayerType layer_type)
Definition SupportLayer.hpp:126
SupporLayerType
Definition SupportLayer.hpp:15
std::vector< SupportGeneratorLayer * > SupportGeneratorLayersPtr
Definition SupportLayer.hpp:142
Slic3r::Polygons union_(const Slic3r::Polygons &subject)
Definition ClipperUtils.cpp:704
void smooth_outward(MutablePolygon &polygon, coord_t clip_dist_scaled)
Definition MutablePolygon.cpp:261
Slic3r::Polygons intersection(const Slic3r::Polygon &subject, const Slic3r::Polygon &clip, ApplySafetyOffset do_safety_offset)
Definition ClipperUtils.cpp:686
Slic3r::Polygons closing(const Slic3r::Polygons &polygons, const float delta1, const float delta2, ClipperLib::JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:587
Slic3r::Polygons union_safety_offset(const Slic3r::Polygons &polygons)
Definition ClipperUtils.hpp:352
@ smsGrid
Definition PrintConfig.hpp:90
@ smsSnug
Definition PrintConfig.hpp:90
Slic3r::Polygons diff(const Slic3r::Polygon &subject, const Slic3r::Polygon &clip, ApplySafetyOffset do_safety_offset)
Definition ClipperUtils.cpp:672
bool has_base_interfaces() const
Definition SupportParameters.hpp:37
bool has_interfaces() const
Definition SupportParameters.hpp:36
coordf_t interface_density
Definition SupportParameters.hpp:64
Flow support_material_interface_flow
Definition SupportParameters.hpp:47

References Slic3r::FFFSupport::SupportGeneratorLayerStorage::allocate(), Slic3r::append(), Slic3r::FFFSupport::SupportGeneratorLayer::bottom_z, Slic3r::FFFSupport::SupportGeneratorLayer::bridging, Slic3r::closing(), Slic3r::diff(), Slic3r::FFFSupport::SupportParameters::has_base_interfaces(), Slic3r::FFFSupport::SupportParameters::has_interfaces(), Slic3r::FFFSupport::SupportGeneratorLayer::height, Slic3r::FFFSupport::SupportParameters::interface_density, Slic3r::intersection(), Slic3r::FFFSupport::SupportGeneratorLayer::polygons, Slic3r::FFFSupport::SupportGeneratorLayer::print_z, Slic3r::range(), Slic3r::Flow::scaled_spacing(), Slic3r::smooth_outward(), Slic3r::smsGrid, Slic3r::smsSnug, Slic3r::FFFSupport::SupportParameters::support_material_interface_flow, SUPPORT_SURFACES_OFFSET_PARAMETERS, Slic3r::union_(), and Slic3r::union_safety_offset().

Referenced by Slic3r::PrintObjectSupportMaterial::generate(), and Slic3r::FFFTreeSupport::generate_support_areas().

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

◆ generate_raft_base()

SupportGeneratorLayersPtr Slic3r::FFFSupport::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 
)
321{
322 // If there is brim to be generated, calculate the trimming regions.
323 Polygons brim;
324 if (object.has_brim()) {
325 // The object does not have a raft.
326 // Calculate the area covered by the brim.
327 const BrimType brim_type = object.config().brim_type;
328 const bool brim_outer = brim_type == btOuterOnly || brim_type == btOuterAndInner;
329 const bool brim_inner = brim_type == btInnerOnly || brim_type == btOuterAndInner;
330 const auto brim_separation = scaled<float>(object.config().brim_separation.value + object.config().brim_width.value);
331 for (const ExPolygon &ex : object.layers().front()->lslices) {
332 if (brim_outer && brim_inner)
333 polygons_append(brim, offset(ex, brim_separation));
334 else {
335 if (brim_outer)
336 polygons_append(brim, offset(ex.contour, brim_separation, ClipperLib::jtRound, float(scale_(0.1))));
337 else
338 brim.emplace_back(ex.contour);
339 if (brim_inner) {
340 Polygons holes = ex.holes;
341 polygons_reverse(holes);
342 holes = shrink(holes, brim_separation, ClipperLib::jtRound, float(scale_(0.1)));
343 polygons_reverse(holes);
344 polygons_append(brim, std::move(holes));
345 } else
346 polygons_append(brim, ex.holes);
347 }
348 }
349 brim = union_(brim);
350 }
351
352 // How much to inflate the support columns to be stable. This also applies to the 1st layer, if no raft layers are to be printed.
353 const float inflate_factor_fine = float(scale_((slicing_params.raft_layers() > 1) ? 0.5 : EPSILON));
354 const float inflate_factor_1st_layer = std::max(0.f, float(scale_(object.config().raft_first_layer_expansion)) - inflate_factor_fine);
355 SupportGeneratorLayer *contacts = top_contacts .empty() ? nullptr : top_contacts .front();
356 SupportGeneratorLayer *interfaces = interface_layers .empty() ? nullptr : interface_layers .front();
357 SupportGeneratorLayer *base_interfaces = base_interface_layers.empty() ? nullptr : base_interface_layers.front();
358 SupportGeneratorLayer *columns_base = base_layers .empty() ? nullptr : base_layers .front();
359 if (contacts != nullptr && contacts->print_z > std::max(slicing_params.first_print_layer_height, slicing_params.raft_contact_top_z) + EPSILON)
360 // This is not the raft contact layer.
361 contacts = nullptr;
362 if (interfaces != nullptr && interfaces->bottom_print_z() > slicing_params.raft_interface_top_z + EPSILON)
363 // This is not the raft column base layer.
364 interfaces = nullptr;
365 if (base_interfaces != nullptr && base_interfaces->bottom_print_z() > slicing_params.raft_interface_top_z + EPSILON)
366 // This is not the raft column base layer.
367 base_interfaces = nullptr;
368 if (columns_base != nullptr && columns_base->bottom_print_z() > slicing_params.raft_interface_top_z + EPSILON)
369 // This is not the raft interface layer.
370 columns_base = nullptr;
371
372 Polygons interface_polygons;
373 if (contacts != nullptr && ! contacts->polygons.empty())
374 polygons_append(interface_polygons, expand(contacts->polygons, inflate_factor_fine, SUPPORT_SURFACES_OFFSET_PARAMETERS));
375 if (interfaces != nullptr && ! interfaces->polygons.empty())
376 polygons_append(interface_polygons, expand(interfaces->polygons, inflate_factor_fine, SUPPORT_SURFACES_OFFSET_PARAMETERS));
377 if (base_interfaces != nullptr && ! base_interfaces->polygons.empty())
378 polygons_append(interface_polygons, expand(base_interfaces->polygons, inflate_factor_fine, SUPPORT_SURFACES_OFFSET_PARAMETERS));
379
380 // Output vector.
381 SupportGeneratorLayersPtr raft_layers;
382
383 if (slicing_params.raft_layers() > 1) {
384 Polygons base;
385 Polygons columns;
386 Polygons first_layer;
387 if (columns_base != nullptr) {
388 if (columns_base->bottom_print_z() > slicing_params.raft_interface_top_z - EPSILON) {
389 // Classic supports with colums above the raft interface.
390 base = columns_base->polygons;
391 columns = base;
392 if (! interface_polygons.empty())
393 // Trim the 1st layer columns with the inflated interface polygons.
394 columns = diff(columns, interface_polygons);
395 } else {
396 // Organic supports with raft on print bed.
397 assert(is_approx(columns_base->print_z, slicing_params.first_print_layer_height));
398 first_layer = columns_base->polygons;
399 }
400 }
401 if (! interface_polygons.empty()) {
402 // Merge the untrimmed columns base with the expanded raft interface, to be used for the support base and interface.
403 base = union_(base, interface_polygons);
404 }
405 // Do not add the raft contact layer, only add the raft layers below the contact layer.
406 // Insert the 1st layer.
407 {
408 SupportGeneratorLayer &new_layer = layer_storage.allocate_unguarded(slicing_params.base_raft_layers > 0 ? SupporLayerType::RaftBase : SupporLayerType::RaftInterface);
409 raft_layers.push_back(&new_layer);
410 new_layer.print_z = slicing_params.first_print_layer_height;
411 new_layer.height = slicing_params.first_print_layer_height;
412 new_layer.bottom_z = 0.;
413 first_layer = union_(std::move(first_layer), base);
414 new_layer.polygons = inflate_factor_1st_layer > 0 ? expand(first_layer, inflate_factor_1st_layer) : first_layer;
415 }
416 // Insert the base layers.
417 for (size_t i = 1; i < slicing_params.base_raft_layers; ++ i) {
418 coordf_t print_z = raft_layers.back()->print_z;
419 SupportGeneratorLayer &new_layer = layer_storage.allocate_unguarded(SupporLayerType::RaftBase);
420 raft_layers.push_back(&new_layer);
421 new_layer.print_z = print_z + slicing_params.base_raft_layer_height;
422 new_layer.height = slicing_params.base_raft_layer_height;
423 new_layer.bottom_z = print_z;
424 new_layer.polygons = base;
425 }
426 // Insert the interface layers.
427 for (size_t i = 1; i < slicing_params.interface_raft_layers; ++ i) {
428 coordf_t print_z = raft_layers.back()->print_z;
429 SupportGeneratorLayer &new_layer = layer_storage.allocate_unguarded(SupporLayerType::RaftInterface);
430 raft_layers.push_back(&new_layer);
431 new_layer.print_z = print_z + slicing_params.interface_raft_layer_height;
432 new_layer.height = slicing_params.interface_raft_layer_height;
433 new_layer.bottom_z = print_z;
434 new_layer.polygons = interface_polygons;
435 //FIXME misusing contact_polygons for support columns.
436 new_layer.contact_polygons = std::make_unique<Polygons>(columns);
437 }
438 } else {
439 if (columns_base != nullptr) {
440 // Expand the bases of the support columns in the 1st layer.
441 Polygons &raft = columns_base->polygons;
442 Polygons trimming = offset(object.layers().front()->lslices, (float)scale_(support_params.gap_xy), SUPPORT_SURFACES_OFFSET_PARAMETERS);
443 if (inflate_factor_1st_layer > SCALED_EPSILON) {
444 // Inflate in multiple steps to avoid leaking of the support 1st layer through object walls.
445 auto nsteps = std::max(5, int(ceil(inflate_factor_1st_layer / support_params.first_layer_flow.scaled_width())));
446 float step = inflate_factor_1st_layer / nsteps;
447 for (int i = 0; i < nsteps; ++ i)
448 raft = diff(expand(raft, step), trimming);
449 } else
450 raft = diff(raft, trimming);
451 if (! interface_polygons.empty())
452 columns_base->polygons = diff(columns_base->polygons, interface_polygons);
453 }
454 if (! brim.empty()) {
455 if (columns_base)
456 columns_base->polygons = diff(columns_base->polygons, brim);
457 if (contacts)
458 contacts->polygons = diff(contacts->polygons, brim);
459 if (interfaces)
460 interfaces->polygons = diff(interfaces->polygons, brim);
461 if (base_interfaces)
462 base_interfaces->polygons = diff(base_interfaces->polygons, brim);
463 }
464 }
465
466 return raft_layers;
467}
EIGEN_DEVICE_FUNC const CeilReturnType ceil() const
Definition ArrayCwiseUnaryOps.h:402
coordf_t print_z
Definition SupportLayer.hpp:91
SupportGeneratorLayer & allocate_unguarded(SupporLayerType layer_type)
Definition SupportLayer.hpp:120
coord_t scaled_width() const
Definition Flow.hpp:61
static constexpr double EPSILON
Definition libslic3r.h:51
double coordf_t
Definition libslic3r.h:45
@ jtRound
Definition clipper.hpp:138
BrimType
Definition PrintConfig.hpp:117
@ btOuterAndInner
Definition PrintConfig.hpp:121
@ btInnerOnly
Definition PrintConfig.hpp:120
@ btOuterOnly
Definition PrintConfig.hpp:119
Slic3r::Polygons expand(const Slic3r::Polygon &polygon, const float delta, ClipperLib::JoinType joinType=DefaultJoinType, double miterLimit=DefaultMiterLimit)
Definition ClipperUtils.hpp:363
void polygons_reverse(Polygons &polys)
Definition Polygon.hpp:163
Slic3r::Polygons shrink(const Slic3r::Polygons &polygons, const float delta, ClipperLib::JoinType joinType=DefaultJoinType, double miterLimit=DefaultMiterLimit)
Definition ClipperUtils.hpp:372
constexpr bool is_approx(Number value, Number test_value, Number precision=EPSILON)
Definition libslic3r.h:271
void polygons_append(Polygons &dst, const ExPolygon &src)
Definition ExPolygon.hpp:375
TPoint< P > front(const P &p)
Definition geometry_traits.hpp:872
void offset(Slic3r::ExPolygon &sh, coord_t distance, const PolygonTag &)
Definition geometries.hpp:132
Coord step(const Coord &crd, Dir d)
Definition MarchingSquares.hpp:137
Flow first_layer_flow
Definition SupportParameters.hpp:42
coordf_t gap_xy
Definition SupportParameters.hpp:58
size_t base_raft_layers
Definition Slicing.hpp:50
coordf_t interface_raft_layer_height
Definition Slicing.hpp:56
coordf_t base_raft_layer_height
Definition Slicing.hpp:55
coordf_t first_print_layer_height
Definition Slicing.hpp:70
coordf_t raft_interface_top_z
Definition Slicing.hpp:94
size_t raft_layers() const
Definition Slicing.hpp:39
size_t interface_raft_layers
Definition Slicing.hpp:52
coordf_t raft_contact_top_z
Definition Slicing.hpp:95

References Slic3r::FFFSupport::SupportGeneratorLayerStorage::allocate_unguarded(), Slic3r::SlicingParameters::base_raft_layer_height, Slic3r::SlicingParameters::base_raft_layers, Slic3r::FFFSupport::SupportGeneratorLayer::bottom_print_z(), Slic3r::FFFSupport::SupportGeneratorLayer::bottom_z, Slic3r::btInnerOnly, Slic3r::btOuterAndInner, Slic3r::btOuterOnly, ceil(), Slic3r::FFFSupport::SupportGeneratorLayer::contact_polygons, Slic3r::diff(), EPSILON, Slic3r::expand(), Slic3r::FFFSupport::SupportParameters::first_layer_flow, Slic3r::SlicingParameters::first_print_layer_height, Slic3r::FFFSupport::SupportParameters::gap_xy, generate_raft_base(), Slic3r::FFFSupport::SupportGeneratorLayer::height, Slic3r::SlicingParameters::interface_raft_layer_height, Slic3r::SlicingParameters::interface_raft_layers, Slic3r::is_approx(), ClipperLib::jtRound, Slic3r::FFFSupport::SupportGeneratorLayer::polygons, Slic3r::polygons_append(), Slic3r::polygons_reverse(), Slic3r::FFFSupport::SupportGeneratorLayer::print_z, Slic3r::SlicingParameters::raft_contact_top_z, Slic3r::SlicingParameters::raft_interface_top_z, Slic3r::SlicingParameters::raft_layers(), scale_, SCALED_EPSILON, Slic3r::Flow::scaled_width(), Slic3r::shrink(), SUPPORT_SURFACES_OFFSET_PARAMETERS, and Slic3r::union_().

Referenced by Slic3r::PrintObjectSupportMaterial::generate(), generate_raft_base(), and Slic3r::FFFTreeSupport::generate_support_areas().

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

◆ generate_support_layers()

SupportGeneratorLayersPtr Slic3r::FFFSupport::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 
)
1389{
1390 // Install support layers into the object.
1391 // A support layer installed on a PrintObject has a unique print_z.
1392 SupportGeneratorLayersPtr layers_sorted;
1393 layers_sorted.reserve(raft_layers.size() + bottom_contacts.size() + top_contacts.size() + intermediate_layers.size() + interface_layers.size() + base_interface_layers.size());
1394 append(layers_sorted, raft_layers);
1395 append(layers_sorted, bottom_contacts);
1396 append(layers_sorted, top_contacts);
1397 append(layers_sorted, intermediate_layers);
1398 append(layers_sorted, interface_layers);
1399 append(layers_sorted, base_interface_layers);
1400 // Sort the layers lexicographically by a raising print_z and a decreasing height.
1401 std::sort(layers_sorted.begin(), layers_sorted.end(), [](auto *l1, auto *l2) { return *l1 < *l2; });
1402 int layer_id = 0;
1403 int layer_id_interface = 0;
1404 assert(object.support_layers().empty());
1405 for (size_t i = 0; i < layers_sorted.size();) {
1406 // Find the last layer with roughly the same print_z, find the minimum layer height of all.
1407 // Due to the floating point inaccuracies, the print_z may not be the same even if in theory they should.
1408 size_t j = i + 1;
1409 coordf_t zmax = layers_sorted[i]->print_z + EPSILON;
1410 for (; j < layers_sorted.size() && layers_sorted[j]->print_z <= zmax; ++j) ;
1411 // Assign an average print_z to the set of layers with nearly equal print_z.
1412 coordf_t zavg = 0.5 * (layers_sorted[i]->print_z + layers_sorted[j - 1]->print_z);
1413 coordf_t height_min = layers_sorted[i]->height;
1414 bool empty = true;
1415 // For snug supports, layers where the direction of the support interface shall change are accounted for.
1416 size_t num_interfaces = 0;
1417 size_t num_top_contacts = 0;
1418 double top_contact_bottom_z = 0;
1419 for (size_t u = i; u < j; ++u) {
1420 SupportGeneratorLayer &layer = *layers_sorted[u];
1421 if (! layer.polygons.empty()) {
1422 empty = false;
1423 num_interfaces += one_of(layer.layer_type, support_types_interface);
1424 if (layer.layer_type == SupporLayerType::TopContact) {
1425 ++ num_top_contacts;
1426 assert(num_top_contacts <= 1);
1427 // All top contact layers sharing this print_z shall also share bottom_z.
1428 //assert(num_top_contacts == 1 || (top_contact_bottom_z - layer.bottom_z) < EPSILON);
1429 top_contact_bottom_z = layer.bottom_z;
1430 }
1431 }
1432 layer.print_z = zavg;
1433 height_min = std::min(height_min, layer.height);
1434 }
1435 if (! empty) {
1436 // Here the upper_layer and lower_layer pointers are left to null at the support layers,
1437 // as they are never used. These pointers are candidates for removal.
1438 bool this_layer_contacts_only = num_top_contacts > 0 && num_top_contacts == num_interfaces;
1439 size_t this_layer_id_interface = layer_id_interface;
1440 if (this_layer_contacts_only) {
1441 // Find a supporting layer for its interface ID.
1442 for (auto it = object.support_layers().rbegin(); it != object.support_layers().rend(); ++ it)
1443 if (const SupportLayer &other_layer = **it; std::abs(other_layer.print_z - top_contact_bottom_z) < EPSILON) {
1444 // other_layer supports this top contact layer. Assign a different support interface direction to this layer
1445 // from the layer that supports it.
1446 this_layer_id_interface = other_layer.interface_id() + 1;
1447 }
1448 }
1449 object.add_support_layer(layer_id ++, this_layer_id_interface, height_min, zavg);
1450 if (num_interfaces && ! this_layer_contacts_only)
1451 ++ layer_id_interface;
1452 }
1453 i = j;
1454 }
1455 return layers_sorted;
1456}
coordf_t height
Definition SupportLayer.hpp:96
SupporLayerType layer_type
Definition SupportLayer.hpp:89
coordf_t bottom_z
Definition SupportLayer.hpp:94
double coordf_t
Definition GUI_ObjectList.hpp:36
bool one_of(const ValueType &v, const ContainerType &c)
Definition libslic3r.h:252
bool empty(const BoundingBoxBase< PointType, PointsType > &bb)
Definition BoundingBox.hpp:229
auto rbegin(P &p) -> decltype(_backward(end(p)))
Definition geometry_traits.hpp:852
auto rend(P &p) -> decltype(_backward(begin(p)))
Definition geometry_traits.hpp:862

References Slic3r::FFFSupport::SupportGeneratorLayer::bottom_z, Slic3r::empty(), EPSILON, generate_support_layers(), Slic3r::FFFSupport::SupportGeneratorLayer::height, Slic3r::l2(), Slic3r::FFFSupport::SupportGeneratorLayer::layer_type, Slic3r::one_of(), Slic3r::FFFSupport::SupportGeneratorLayer::polygons, Slic3r::FFFSupport::SupportGeneratorLayer::print_z, and support_types_interface.

Referenced by Slic3r::PrintObjectSupportMaterial::generate(), Slic3r::FFFTreeSupport::generate_support_areas(), and generate_support_layers().

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

◆ generate_support_toolpaths()

void Slic3r::FFFSupport::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 
)
1469{
1470 // loop_interface_processor with a given circle radius.
1471 LoopInterfaceProcessor loop_interface_processor(1.5 * support_params.support_material_interface_flow.scaled_width());
1472 loop_interface_processor.n_contact_loops = config.support_material_interface_contact_loops ? 1 : 0;
1473
1474 std::vector<float> angles { support_params.base_angle };
1475 if (config.support_material_pattern == smpRectilinearGrid)
1476 angles.push_back(support_params.interface_angle);
1477
1478 BoundingBox bbox_object(Point(-scale_(1.), -scale_(1.0)), Point(scale_(1.), scale_(1.)));
1479
1480// const coordf_t link_max_length_factor = 3.;
1481 const coordf_t link_max_length_factor = 0.;
1482
1483 // Insert the raft base layers.
1484 auto n_raft_layers = std::min<size_t>(support_layers.size(), std::max(0, int(slicing_params.raft_layers()) - 1));
1485
1486 tbb::parallel_for(tbb::blocked_range<size_t>(0, n_raft_layers),
1487 [&support_layers, &raft_layers, &intermediate_layers, &config, &support_params, &slicing_params,
1488 &bbox_object, link_max_length_factor]
1489 (const tbb::blocked_range<size_t>& range) {
1490 for (size_t support_layer_id = range.begin(); support_layer_id < range.end(); ++ support_layer_id)
1491 {
1492 assert(support_layer_id < raft_layers.size());
1493 SupportLayer &support_layer = *support_layers[support_layer_id];
1494 assert(support_layer.support_fills.entities.empty());
1495 SupportGeneratorLayer &raft_layer = *raft_layers[support_layer_id];
1496
1497 std::unique_ptr<Fill> filler_interface = std::unique_ptr<Fill>(Fill::new_from_type(support_params.raft_interface_fill_pattern));
1498 std::unique_ptr<Fill> filler_support = std::unique_ptr<Fill>(Fill::new_from_type(support_params.base_fill_pattern));
1499 filler_interface->set_bounding_box(bbox_object);
1500 filler_support->set_bounding_box(bbox_object);
1501
1502 // Print the tree supports cutting through the raft with the exception of the 1st layer, where a full support layer will be printed below
1503 // both the raft and the trees.
1504 // Trim the raft layers with the tree polygons.
1505 const Polygons &tree_polygons =
1506 support_layer_id > 0 && support_layer_id < intermediate_layers.size() && is_approx(intermediate_layers[support_layer_id]->print_z, support_layer.print_z) ?
1507 intermediate_layers[support_layer_id]->polygons : Polygons();
1508
1509 // Print the support base below the support columns, or the support base for the support columns plus the contacts.
1510 if (support_layer_id > 0) {
1511 const Polygons &to_infill_polygons = (support_layer_id < slicing_params.base_raft_layers) ?
1512 raft_layer.polygons :
1513 //FIXME misusing contact_polygons for support columns.
1514 ((raft_layer.contact_polygons == nullptr) ? Polygons() : *raft_layer.contact_polygons);
1515 // Trees may cut through the raft layers down to a print bed.
1516 Flow flow(float(support_params.support_material_flow.width()), float(raft_layer.height), support_params.support_material_flow.nozzle_diameter());
1517 assert(!raft_layer.bridging);
1518 if (! to_infill_polygons.empty()) {
1519 Fill *filler = filler_support.get();
1520 filler->angle = support_params.raft_angle_base;
1521 filler->spacing = support_params.support_material_flow.spacing();
1522 filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / support_params.support_density));
1523 fill_expolygons_with_sheath_generate_paths(
1524 // Destination
1525 support_layer.support_fills.entities,
1526 // Regions to fill
1527 tree_polygons.empty() ? to_infill_polygons : diff(to_infill_polygons, tree_polygons),
1528 // Filler and its parameters
1529 filler, float(support_params.support_density),
1530 // Extrusion parameters
1532 support_params.with_sheath, false);
1533 }
1534 if (! tree_polygons.empty())
1535 tree_supports_generate_paths(support_layer.support_fills.entities, tree_polygons, flow, support_params);
1536 }
1537
1538 Fill *filler = filler_interface.get();
1539 Flow flow = support_params.first_layer_flow;
1540 float density = 0.f;
1541 if (support_layer_id == 0) {
1542 // Base flange.
1543 filler->angle = support_params.raft_angle_1st_layer;
1544 filler->spacing = support_params.first_layer_flow.spacing();
1545 density = float(config.raft_first_layer_density.value * 0.01);
1546 } else if (support_layer_id >= slicing_params.base_raft_layers) {
1547 filler->angle = support_params.raft_interface_angle(support_layer.interface_id());
1548 // We don't use $base_flow->spacing because we need a constant spacing
1549 // value that guarantees that all layers are correctly aligned.
1550 filler->spacing = support_params.support_material_flow.spacing();
1551 assert(! raft_layer.bridging);
1552 flow = Flow(float(support_params.raft_interface_flow.width()), float(raft_layer.height), support_params.raft_interface_flow.nozzle_diameter());
1553 density = float(support_params.raft_interface_density);
1554 } else
1555 continue;
1556 filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / density));
1558 // Destination
1559 support_layer.support_fills.entities,
1560 // Regions to fill
1561 tree_polygons.empty() ? raft_layer.polygons : diff(raft_layer.polygons, tree_polygons),
1562 // Filler and its parameters
1563 filler, density,
1564 // Extrusion parameters
1565 (support_layer_id < slicing_params.base_raft_layers) ? ExtrusionRole::SupportMaterial : ExtrusionRole::SupportMaterialInterface, flow,
1566 // sheath at first layer
1567 support_layer_id == 0, support_layer_id == 0);
1568 }
1569 });
1570
1571 struct LayerCacheItem {
1572 LayerCacheItem(SupportGeneratorLayerExtruded *layer_extruded = nullptr) : layer_extruded(layer_extruded) {}
1573 SupportGeneratorLayerExtruded *layer_extruded;
1574 std::vector<SupportGeneratorLayer*> overlapping;
1575 };
1576 struct LayerCache {
1577 SupportGeneratorLayerExtruded bottom_contact_layer;
1578 SupportGeneratorLayerExtruded top_contact_layer;
1579 SupportGeneratorLayerExtruded base_layer;
1580 SupportGeneratorLayerExtruded interface_layer;
1581 SupportGeneratorLayerExtruded base_interface_layer;
1582 boost::container::static_vector<LayerCacheItem, 5> nonempty;
1583
1584 void add_nonempty_and_sort() {
1585 for (SupportGeneratorLayerExtruded *item : { &bottom_contact_layer, &top_contact_layer, &interface_layer, &base_interface_layer, &base_layer })
1586 if (! item->empty())
1587 this->nonempty.emplace_back(item);
1588 // Sort the layers with the same print_z coordinate by their heights, thickest first.
1589 std::stable_sort(this->nonempty.begin(), this->nonempty.end(), [](const LayerCacheItem &lc1, const LayerCacheItem &lc2) { return lc1.layer_extruded->layer->height > lc2.layer_extruded->layer->height; });
1590 }
1591 };
1592 std::vector<LayerCache> layer_caches(support_layers.size());
1593
1594 tbb::parallel_for(tbb::blocked_range<size_t>(n_raft_layers, support_layers.size()),
1595 [&config, &slicing_params, &support_params, &support_layers, &bottom_contacts, &top_contacts, &intermediate_layers, &interface_layers, &base_interface_layers, &layer_caches, &loop_interface_processor,
1596 &bbox_object, &angles, n_raft_layers, link_max_length_factor]
1597 (const tbb::blocked_range<size_t>& range) {
1598 // Indices of the 1st layer in their respective container at the support layer height.
1599 size_t idx_layer_bottom_contact = size_t(-1);
1600 size_t idx_layer_top_contact = size_t(-1);
1601 size_t idx_layer_intermediate = size_t(-1);
1602 size_t idx_layer_interface = size_t(-1);
1603 size_t idx_layer_base_interface = size_t(-1);
1604 const auto fill_type_first_layer = ipRectilinear;
1605 auto filler_interface = std::unique_ptr<Fill>(Fill::new_from_type(support_params.contact_fill_pattern));
1606 // Filler for the 1st layer interface, if different from filler_interface.
1607 auto filler_first_layer_ptr = std::unique_ptr<Fill>(range.begin() == 0 && support_params.contact_fill_pattern != fill_type_first_layer ? Fill::new_from_type(fill_type_first_layer) : nullptr);
1608 // Pointer to the 1st layer interface filler.
1609 auto filler_first_layer = filler_first_layer_ptr ? filler_first_layer_ptr.get() : filler_interface.get();
1610 // Filler for the 1st layer interface, if different from filler_interface.
1611 auto filler_raft_contact_ptr = std::unique_ptr<Fill>(range.begin() == n_raft_layers && config.support_material_interface_layers.value == 0 ?
1612 Fill::new_from_type(support_params.raft_interface_fill_pattern) : nullptr);
1613 // Pointer to the 1st layer interface filler.
1614 auto filler_raft_contact = filler_raft_contact_ptr ? filler_raft_contact_ptr.get() : filler_interface.get();
1615 // Filler for the base interface (to be used for soluble interface / non soluble base, to produce non soluble interface layer below soluble interface layer).
1616 auto filler_base_interface = std::unique_ptr<Fill>(base_interface_layers.empty() ? nullptr :
1617 Fill::new_from_type(support_params.interface_density > 0.95 || support_params.with_sheath ? ipRectilinear : ipSupportBase));
1618 auto filler_support = std::unique_ptr<Fill>(Fill::new_from_type(support_params.base_fill_pattern));
1619 filler_interface->set_bounding_box(bbox_object);
1620 if (filler_first_layer_ptr)
1621 filler_first_layer_ptr->set_bounding_box(bbox_object);
1622 if (filler_raft_contact_ptr)
1623 filler_raft_contact_ptr->set_bounding_box(bbox_object);
1624 if (filler_base_interface)
1625 filler_base_interface->set_bounding_box(bbox_object);
1626 filler_support->set_bounding_box(bbox_object);
1627 for (size_t support_layer_id = range.begin(); support_layer_id < range.end(); ++ support_layer_id)
1628 {
1629 SupportLayer &support_layer = *support_layers[support_layer_id];
1630 LayerCache &layer_cache = layer_caches[support_layer_id];
1631 const float support_interface_angle = config.support_material_style.value == smsGrid ?
1632 support_params.interface_angle : support_params.raft_interface_angle(support_layer.interface_id());
1633
1634 // Find polygons with the same print_z.
1635 SupportGeneratorLayerExtruded &bottom_contact_layer = layer_cache.bottom_contact_layer;
1636 SupportGeneratorLayerExtruded &top_contact_layer = layer_cache.top_contact_layer;
1637 SupportGeneratorLayerExtruded &base_layer = layer_cache.base_layer;
1638 SupportGeneratorLayerExtruded &interface_layer = layer_cache.interface_layer;
1639 SupportGeneratorLayerExtruded &base_interface_layer = layer_cache.base_interface_layer;
1640 // Increment the layer indices to find a layer at support_layer.print_z.
1641 {
1642 auto fun = [&support_layer](const SupportGeneratorLayer *l){ return l->print_z >= support_layer.print_z - EPSILON; };
1643 idx_layer_bottom_contact = idx_higher_or_equal(bottom_contacts, idx_layer_bottom_contact, fun);
1644 idx_layer_top_contact = idx_higher_or_equal(top_contacts, idx_layer_top_contact, fun);
1645 idx_layer_intermediate = idx_higher_or_equal(intermediate_layers, idx_layer_intermediate, fun);
1646 idx_layer_interface = idx_higher_or_equal(interface_layers, idx_layer_interface, fun);
1647 idx_layer_base_interface = idx_higher_or_equal(base_interface_layers, idx_layer_base_interface,fun);
1648 }
1649 // Copy polygons from the layers.
1650 if (idx_layer_bottom_contact < bottom_contacts.size() && bottom_contacts[idx_layer_bottom_contact]->print_z < support_layer.print_z + EPSILON)
1651 bottom_contact_layer.layer = bottom_contacts[idx_layer_bottom_contact];
1652 if (idx_layer_top_contact < top_contacts.size() && top_contacts[idx_layer_top_contact]->print_z < support_layer.print_z + EPSILON)
1653 top_contact_layer.layer = top_contacts[idx_layer_top_contact];
1654 if (idx_layer_interface < interface_layers.size() && interface_layers[idx_layer_interface]->print_z < support_layer.print_z + EPSILON)
1655 interface_layer.layer = interface_layers[idx_layer_interface];
1656 if (idx_layer_base_interface < base_interface_layers.size() && base_interface_layers[idx_layer_base_interface]->print_z < support_layer.print_z + EPSILON)
1657 base_interface_layer.layer = base_interface_layers[idx_layer_base_interface];
1658 if (idx_layer_intermediate < intermediate_layers.size() && intermediate_layers[idx_layer_intermediate]->print_z < support_layer.print_z + EPSILON)
1659 base_layer.layer = intermediate_layers[idx_layer_intermediate];
1660
1661 // This layer is a raft contact layer. Any contact polygons at this layer are raft contacts.
1662 bool raft_layer = slicing_params.interface_raft_layers && top_contact_layer.layer && is_approx(top_contact_layer.layer->print_z, slicing_params.raft_contact_top_z);
1663 if (config.support_material_interface_layers == 0) {
1664 // If no top interface layers were requested, we treat the contact layer exactly as a generic base layer.
1665 // Don't merge the raft contact layer though.
1666 if (support_params.can_merge_support_regions && ! raft_layer) {
1667 if (base_layer.could_merge(top_contact_layer))
1668 base_layer.merge(std::move(top_contact_layer));
1669 else if (base_layer.empty())
1670 base_layer = std::move(top_contact_layer);
1671 }
1672 } else {
1673 loop_interface_processor.generate(top_contact_layer, support_params.support_material_interface_flow);
1674 // If no loops are allowed, we treat the contact layer exactly as a generic interface layer.
1675 // Merge interface_layer into top_contact_layer, as the top_contact_layer is not synchronized and therefore it will be used
1676 // to trim other layers.
1677 if (top_contact_layer.could_merge(interface_layer) && ! raft_layer)
1678 top_contact_layer.merge(std::move(interface_layer));
1679 }
1680 if ((config.support_material_interface_layers == 0 || config.support_material_bottom_interface_layers == 0) && support_params.can_merge_support_regions) {
1681 if (base_layer.could_merge(bottom_contact_layer))
1682 base_layer.merge(std::move(bottom_contact_layer));
1683 else if (base_layer.empty() && ! bottom_contact_layer.empty() && ! bottom_contact_layer.layer->bridging)
1684 base_layer = std::move(bottom_contact_layer);
1685 } else if (bottom_contact_layer.could_merge(top_contact_layer) && ! raft_layer)
1686 top_contact_layer.merge(std::move(bottom_contact_layer));
1687 else if (bottom_contact_layer.could_merge(interface_layer))
1688 bottom_contact_layer.merge(std::move(interface_layer));
1689
1690#if 0
1691 if ( ! interface_layer.empty() && ! base_layer.empty()) {
1692 // turn base support into interface when it's contained in our holes
1693 // (this way we get wider interface anchoring)
1694 //FIXME The intention of the code below is unclear. One likely wanted to just merge small islands of base layers filling in the holes
1695 // inside interface layers, but the code below fills just too much, see GH #4570
1696 Polygons islands = top_level_islands(interface_layer.layer->polygons);
1697 polygons_append(interface_layer.layer->polygons, intersection(base_layer.layer->polygons, islands));
1698 base_layer.layer->polygons = diff(base_layer.layer->polygons, islands);
1699 }
1700#endif
1701
1702 // Top and bottom contacts, interface layers.
1703 enum class InterfaceLayerType { TopContact, BottomContact, RaftContact, Interface, InterfaceAsBase };
1704 auto extrude_interface = [&](SupportGeneratorLayerExtruded &layer_ex, InterfaceLayerType interface_layer_type) {
1705 if (! layer_ex.empty() && ! layer_ex.polygons_to_extrude().empty()) {
1706 bool interface_as_base = interface_layer_type == InterfaceLayerType::InterfaceAsBase;
1707 bool raft_contact = interface_layer_type == InterfaceLayerType::RaftContact;
1708 //FIXME Bottom interfaces are extruded with the briding flow. Some bridging layers have its height slightly reduced, therefore
1709 // the bridging flow does not quite apply. Reduce the flow to area of an ellipse? (A = pi * a * b)
1710 auto *filler = raft_contact ? filler_raft_contact : filler_interface.get();
1711 auto interface_flow = layer_ex.layer->bridging ?
1712 Flow::bridging_flow(layer_ex.layer->height, support_params.support_material_bottom_interface_flow.nozzle_diameter()) :
1713 (raft_contact ? &support_params.raft_interface_flow :
1714 interface_as_base ? &support_params.support_material_flow : &support_params.support_material_interface_flow)
1715 ->with_height(float(layer_ex.layer->height));
1716 filler->angle = interface_as_base ?
1717 // If zero interface layers are configured, use the same angle as for the base layers.
1718 angles[support_layer_id % angles.size()] :
1719 // Use interface angle for the interface layers.
1720 raft_contact ?
1721 support_params.raft_interface_angle(support_layer.interface_id()) :
1722 support_interface_angle;
1723 double density = raft_contact ? support_params.raft_interface_density : interface_as_base ? support_params.support_density : support_params.interface_density;
1724 filler->spacing = raft_contact ? support_params.raft_interface_flow.spacing() :
1725 interface_as_base ? support_params.support_material_flow.spacing() : support_params.support_material_interface_flow.spacing();
1726 filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / density));
1727 fill_expolygons_generate_paths(
1728 // Destination
1729 layer_ex.extrusions,
1730 // Regions to fill
1731 union_safety_offset_ex(layer_ex.polygons_to_extrude()),
1732 // Filler and its parameters
1733 filler, float(density),
1734 // Extrusion parameters
1735 ExtrusionRole::SupportMaterialInterface, interface_flow);
1736 }
1737 };
1738 const bool top_interfaces = config.support_material_interface_layers.value != 0;
1739 const bool bottom_interfaces = top_interfaces && config.support_material_bottom_interface_layers != 0;
1740 extrude_interface(top_contact_layer, raft_layer ? InterfaceLayerType::RaftContact : top_interfaces ? InterfaceLayerType::TopContact : InterfaceLayerType::InterfaceAsBase);
1741 extrude_interface(bottom_contact_layer, bottom_interfaces ? InterfaceLayerType::BottomContact : InterfaceLayerType::InterfaceAsBase);
1742 extrude_interface(interface_layer, top_interfaces ? InterfaceLayerType::Interface : InterfaceLayerType::InterfaceAsBase);
1743
1744 // Base interface layers under soluble interfaces
1745 if ( ! base_interface_layer.empty() && ! base_interface_layer.polygons_to_extrude().empty()) {
1746 Fill *filler = filler_base_interface.get();
1747 //FIXME Bottom interfaces are extruded with the briding flow. Some bridging layers have its height slightly reduced, therefore
1748 // the bridging flow does not quite apply. Reduce the flow to area of an ellipse? (A = pi * a * b)
1749 assert(! base_interface_layer.layer->bridging);
1750 Flow interface_flow = support_params.support_material_flow.with_height(float(base_interface_layer.layer->height));
1751 filler->angle = support_interface_angle;
1752 filler->spacing = support_params.support_material_interface_flow.spacing();
1753 filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / support_params.interface_density));
1754 fill_expolygons_generate_paths(
1755 // Destination
1756 base_interface_layer.extrusions,
1757 //base_layer_interface.extrusions,
1758 // Regions to fill
1759 union_safety_offset_ex(base_interface_layer.polygons_to_extrude()),
1760 // Filler and its parameters
1761 filler, float(support_params.interface_density),
1762 // Extrusion parameters
1763 ExtrusionRole::SupportMaterial, interface_flow);
1764 }
1765
1766 // Base support or flange.
1767 if (! base_layer.empty() && ! base_layer.polygons_to_extrude().empty()) {
1768 Fill *filler = filler_support.get();
1769 filler->angle = angles[support_layer_id % angles.size()];
1770 // We don't use $base_flow->spacing because we need a constant spacing
1771 // value that guarantees that all layers are correctly aligned.
1772 assert(! base_layer.layer->bridging);
1773 auto flow = support_params.support_material_flow.with_height(float(base_layer.layer->height));
1774 filler->spacing = support_params.support_material_flow.spacing();
1775 filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / support_params.support_density));
1776 float density = float(support_params.support_density);
1777 bool sheath = support_params.with_sheath;
1778 bool no_sort = false;
1779 bool done = false;
1780 if (base_layer.layer->bottom_z < EPSILON) {
1781 // Base flange (the 1st layer).
1782 filler = filler_first_layer;
1783 filler->angle = Geometry::deg2rad(float(config.support_material_angle.value + 90.));
1784 density = float(config.raft_first_layer_density.value * 0.01);
1785 flow = support_params.first_layer_flow;
1786 // use the proper spacing for first layer as we don't need to align
1787 // its pattern to the other layers
1788 //FIXME When paralellizing, each thread shall have its own copy of the fillers.
1789 filler->spacing = flow.spacing();
1790 filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / density));
1791 sheath = true;
1792 no_sort = true;
1793 } else if (config.support_material_style == SupportMaterialStyle::smsOrganic) {
1794 tree_supports_generate_paths(base_layer.extrusions, base_layer.polygons_to_extrude(), flow, support_params);
1795 done = true;
1796 }
1797 if (! done)
1798 fill_expolygons_with_sheath_generate_paths(
1799 // Destination
1800 base_layer.extrusions,
1801 // Regions to fill
1802 base_layer.polygons_to_extrude(),
1803 // Filler and its parameters
1804 filler, density,
1805 // Extrusion parameters
1806 ExtrusionRole::SupportMaterial, flow,
1807 sheath, no_sort);
1808 }
1809
1810 // Merge base_interface_layers to base_layers to avoid unneccessary retractions
1811 if (! base_layer.empty() && ! base_interface_layer.empty() && ! base_layer.polygons_to_extrude().empty() && ! base_interface_layer.polygons_to_extrude().empty() &&
1812 base_layer.could_merge(base_interface_layer))
1813 base_layer.merge(std::move(base_interface_layer));
1814
1815 layer_cache.add_nonempty_and_sort();
1816
1817 // Collect the support areas with this print_z into islands, as there is no need
1818 // for retraction over these islands.
1819 Polygons polys;
1820 // Collect the extrusions, sorted by the bottom extrusion height.
1821 for (LayerCacheItem &layer_cache_item : layer_cache.nonempty) {
1822 // Collect islands to polys.
1823 layer_cache_item.layer_extruded->polygons_append(polys);
1824 // The print_z of the top contact surfaces and bottom_z of the bottom contact surfaces are "free"
1825 // in a sense that they are not synchronized with other support layers. As the top and bottom contact surfaces
1826 // are inflated to achieve a better anchoring, it may happen, that these surfaces will at least partially
1827 // overlap in Z with another support layers, leading to over-extrusion.
1828 // Mitigate the over-extrusion by modulating the extrusion rate over these regions.
1829 // The print head will follow the same print_z, but the layer thickness will be reduced
1830 // where it overlaps with another support layer.
1831 //FIXME When printing a briging path, what is an equivalent height of the squished extrudate of the same width?
1832 // Collect overlapping top/bottom surfaces.
1833 layer_cache_item.overlapping.reserve(20);
1834 coordf_t bottom_z = layer_cache_item.layer_extruded->layer->bottom_print_z() + EPSILON;
1835 auto add_overlapping = [&layer_cache_item, bottom_z](const SupportGeneratorLayersPtr &layers, size_t idx_top) {
1836 for (int i = int(idx_top) - 1; i >= 0 && layers[i]->print_z > bottom_z; -- i)
1837 layer_cache_item.overlapping.push_back(layers[i]);
1838 };
1839 add_overlapping(top_contacts, idx_layer_top_contact);
1840 if (layer_cache_item.layer_extruded->layer->layer_type == SupporLayerType::BottomContact) {
1841 // Bottom contact layer may overlap with a base layer, which may be changed to interface layer.
1842 add_overlapping(intermediate_layers, idx_layer_intermediate);
1843 add_overlapping(interface_layers, idx_layer_interface);
1844 add_overlapping(base_interface_layers, idx_layer_base_interface);
1845 }
1846 // Order the layers by lexicographically by an increasing print_z and a decreasing layer height.
1847 std::stable_sort(layer_cache_item.overlapping.begin(), layer_cache_item.overlapping.end(), [](auto *l1, auto *l2) { return *l1 < *l2; });
1848 }
1849 assert(support_layer.support_islands.empty());
1850 if (! polys.empty()) {
1851 support_layer.support_islands = union_ex(polys);
1852 support_layer.support_islands_bboxes.reserve(support_layer.support_islands.size());
1853 for (const ExPolygon &expoly : support_layer.support_islands)
1854 support_layer.support_islands_bboxes.emplace_back(get_extents(expoly).inflated(SCALED_EPSILON));
1855 }
1856 } // for each support_layer_id
1857 });
1858
1859 // Now modulate the support layer height in parallel.
1860 tbb::parallel_for(tbb::blocked_range<size_t>(n_raft_layers, support_layers.size()),
1861 [&support_layers, &layer_caches]
1862 (const tbb::blocked_range<size_t>& range) {
1863 for (size_t support_layer_id = range.begin(); support_layer_id < range.end(); ++ support_layer_id) {
1864 SupportLayer &support_layer = *support_layers[support_layer_id];
1865 LayerCache &layer_cache = layer_caches[support_layer_id];
1866 // For all extrusion types at this print_z, ordered by decreasing layer height:
1867 for (LayerCacheItem &layer_cache_item : layer_cache.nonempty) {
1868 // Trim the extrusion height from the bottom by the overlapping layers.
1869 modulate_extrusion_by_overlapping_layers(layer_cache_item.layer_extruded->extrusions, *layer_cache_item.layer_extruded->layer, layer_cache_item.overlapping);
1870 support_layer.support_fills.append(std::move(layer_cache_item.layer_extruded->extrusions));
1871 }
1872 }
1873 });
1874
1875#ifndef NDEBUG
1876 struct Test {
1877 static bool verify_nonempty(const ExtrusionEntityCollection *collection) {
1878 for (const ExtrusionEntity *ee : collection->entities) {
1879 if (const ExtrusionPath *path = dynamic_cast<const ExtrusionPath*>(ee))
1880 assert(! path->empty());
1881 else if (const ExtrusionMultiPath *multipath = dynamic_cast<const ExtrusionMultiPath*>(ee))
1882 assert(! multipath->empty());
1883 else if (const ExtrusionEntityCollection *eecol = dynamic_cast<const ExtrusionEntityCollection*>(ee)) {
1884 assert(! eecol->empty());
1885 return verify_nonempty(eecol);
1886 } else
1887 assert(false);
1888 }
1889 return true;
1890 }
1891 };
1892 for (const SupportLayer *support_layer : support_layers)
1893 assert(Test::verify_nonempty(&support_layer->support_fills));
1894#endif // NDEBUG
1895}
ExtrusionEntitiesPtr entities
Definition ExtrusionEntityCollection.hpp:32
Definition FillBase.hpp:70
coordf_t spacing
Definition FillBase.hpp:77
coord_t link_max_length
Definition FillBase.hpp:85
float angle
Definition FillBase.hpp:81
Definition Flow.hpp:52
float spacing() const
Definition Flow.hpp:66
float nozzle_diameter() const
Definition Flow.hpp:69
coordf_t print_z
Definition Layer.hpp:324
Definition Layer.hpp:428
size_t interface_id() const
Definition Layer.hpp:443
static void fill_expolygons_with_sheath_generate_paths(ExtrusionEntitiesPtr &dst, const Polygons &polygons, Fill *filler, float density, ExtrusionRole role, const Flow &flow, bool with_sheath, bool no_sort)
Definition SupportCommon.cpp:763
auto range(Cont &&cont)
Definition libslic3r.h:356
Definition ExtrusionRole.hpp:43
Definition SupportCommon.cpp:883
Flow raft_interface_flow
Definition SupportParameters.hpp:51
InfillPattern base_fill_pattern
Definition SupportParameters.hpp:71
float raft_interface_angle(size_t interface_id) const
Definition SupportParameters.hpp:88
coordf_t raft_interface_density
Definition SupportParameters.hpp:66
coordf_t support_density
Definition SupportParameters.hpp:68
Flow support_material_flow
Definition SupportParameters.hpp:45
float raft_angle_1st_layer
Definition SupportParameters.hpp:83
float raft_angle_base
Definition SupportParameters.hpp:84
float base_angle
Definition SupportParameters.hpp:60
float interface_angle
Definition SupportParameters.hpp:61
InfillPattern raft_interface_fill_pattern
Definition SupportParameters.hpp:75

References Slic3r::Fill::angle, Slic3r::FFFSupport::SupportParameters::base_angle, Slic3r::FFFSupport::SupportParameters::base_fill_pattern, Slic3r::SlicingParameters::base_raft_layers, Slic3r::FFFSupport::SupportGeneratorLayer::bridging, Slic3r::FFFSupport::SupportGeneratorLayer::contact_polygons, Slic3r::diff(), Slic3r::ExtrusionEntityCollection::entities, fill_expolygons_with_sheath_generate_paths(), Slic3r::FFFSupport::SupportParameters::first_layer_flow, generate_support_toolpaths(), Slic3r::FFFSupport::SupportGeneratorLayer::height, Slic3r::FFFSupport::SupportParameters::interface_angle, Slic3r::SupportLayer::interface_id(), Slic3r::is_approx(), Slic3r::Fill::link_max_length, Slic3r::FFFSupport::LoopInterfaceProcessor::n_contact_loops, Slic3r::Flow::nozzle_diameter(), Slic3r::FFFSupport::SupportGeneratorLayer::polygons, Slic3r::Layer::print_z, Slic3r::FFFSupport::SupportParameters::raft_angle_1st_layer, Slic3r::FFFSupport::SupportParameters::raft_angle_base, Slic3r::FFFSupport::SupportParameters::raft_interface_angle(), Slic3r::FFFSupport::SupportParameters::raft_interface_density, Slic3r::FFFSupport::SupportParameters::raft_interface_fill_pattern, Slic3r::FFFSupport::SupportParameters::raft_interface_flow, Slic3r::SlicingParameters::raft_layers(), Slic3r::range(), scale_, Slic3r::Flow::scaled_width(), Slic3r::smpRectilinearGrid, Slic3r::Fill::spacing, Slic3r::Flow::spacing(), Slic3r::FFFSupport::SupportParameters::support_density, Slic3r::SupportLayer::support_fills, Slic3r::FFFSupport::SupportParameters::support_material_flow, Slic3r::FFFSupport::SupportParameters::support_material_interface_flow, tree_supports_generate_paths(), Slic3r::Flow::width(), and Slic3r::FFFSupport::SupportParameters::with_sheath.

Referenced by Slic3r::PrintObjectSupportMaterial::generate(), Slic3r::FFFTreeSupport::generate_support_areas(), and generate_support_toolpaths().

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

◆ idx_higher_or_equal() [1/2]

template<typename T , typename IndexType , typename FN_HIGHER_EQUAL >
IndexType Slic3r::FFFSupport::idx_higher_or_equal ( const std::vector< T > &  vec,
IndexType  idx,
FN_HIGHER_EQUAL  fn_higher_equal 
)
112{
113 return idx_higher_or_equal(vec.begin(), vec.end(), idx, fn_higher_equal);
114}
IndexType idx_higher_or_equal(IteratorType begin, IteratorType end, IndexType idx, FN_HIGHER_EQUAL fn_higher_equal)
Definition SupportCommon.hpp:85

References idx_higher_or_equal().

+ Here is the call graph for this function:

◆ idx_higher_or_equal() [2/2]

template<typename IteratorType , typename IndexType , typename FN_HIGHER_EQUAL >
IndexType Slic3r::FFFSupport::idx_higher_or_equal ( IteratorType  begin,
IteratorType  end,
IndexType  idx,
FN_HIGHER_EQUAL  fn_higher_equal 
)
86{
87 auto size = int(end - begin);
88 if (size == 0) {
89 idx = 0;
90 } else if (idx == IndexType(-1)) {
91 // First of the batch of layers per thread pool invocation. Use binary search.
92 int idx_low = 0;
93 int idx_high = std::max(0, size - 1);
94 while (idx_low + 1 < idx_high) {
95 int idx_mid = (idx_low + idx_high) / 2;
96 if (fn_higher_equal(begin[idx_mid]))
97 idx_high = idx_mid;
98 else
99 idx_low = idx_mid;
100 }
101 idx = fn_higher_equal(begin[idx_low]) ? idx_low :
102 (fn_higher_equal(begin[idx_high]) ? idx_high : size);
103 } else {
104 // For the other layers of this batch of layers, search incrementally, which is cheaper than the binary search.
105 while (int(idx) < size && ! fn_higher_equal(begin[idx]))
106 ++ idx;
107 }
108 return idx;
109}
constexpr auto size(const C &c) -> decltype(c.size())
Definition span.hpp:183

Referenced by idx_higher_or_equal().

+ Here is the caller graph for this function:

◆ idx_lower_or_equal() [1/2]

template<typename T , typename FN_LOWER_EQUAL >
int Slic3r::FFFSupport::idx_lower_or_equal ( const std::vector< T * > &  vec,
int  idx,
FN_LOWER_EQUAL  fn_lower_equal 
)
149{
150 return idx_lower_or_equal(vec.begin(), vec.end(), idx, fn_lower_equal);
151}
int idx_lower_or_equal(IT begin, IT end, int idx, FN_LOWER_EQUAL fn_lower_equal)
Definition SupportCommon.hpp:122

References idx_lower_or_equal().

+ Here is the call graph for this function:

◆ idx_lower_or_equal() [2/2]

template<typename IT , typename FN_LOWER_EQUAL >
int Slic3r::FFFSupport::idx_lower_or_equal ( IT  begin,
IT  end,
int  idx,
FN_LOWER_EQUAL  fn_lower_equal 
)
123{
124 auto size = int(end - begin);
125 if (size == 0) {
126 idx = -1;
127 } else if (idx < -1) {
128 // First of the batch of layers per thread pool invocation. Use binary search.
129 int idx_low = 0;
130 int idx_high = std::max(0, size - 1);
131 while (idx_low + 1 < idx_high) {
132 int idx_mid = (idx_low + idx_high) / 2;
133 if (fn_lower_equal(begin[idx_mid]))
134 idx_low = idx_mid;
135 else
136 idx_high = idx_mid;
137 }
138 idx = fn_lower_equal(begin[idx_high]) ? idx_high :
139 (fn_lower_equal(begin[idx_low ]) ? idx_low : -1);
140 } else {
141 // For the other layers of this batch of layers, search incrementally, which is cheaper than the binary search.
142 while (idx >= 0 && ! fn_lower_equal(begin[idx]))
143 -- idx;
144 }
145 return idx;
146}

Referenced by idx_lower_or_equal().

+ Here is the caller graph for this function:

◆ modulate_extrusion_by_overlapping_layers()

static void Slic3r::FFFSupport::modulate_extrusion_by_overlapping_layers ( ExtrusionEntitiesPtr extrusions_in_out,
const SupportGeneratorLayer this_layer,
const SupportGeneratorLayersPtr overlapping_layers 
)
static
1141{
1142 size_t n_overlapping_layers = overlapping_layers.size();
1143 if (n_overlapping_layers == 0 || extrusions_in_out.empty())
1144 // The extrusions do not overlap with any other extrusion.
1145 return;
1146
1147 // Get the initial extrusion parameters.
1148 ExtrusionPath *extrusion_path_template = dynamic_cast<ExtrusionPath*>(extrusions_in_out.front());
1149 assert(extrusion_path_template != nullptr);
1150 ExtrusionRole extrusion_role = extrusion_path_template->role();
1151 float extrusion_width = extrusion_path_template->width;
1152
1153 struct ExtrusionPathFragment
1154 {
1155 ExtrusionPathFragment() : mm3_per_mm(-1), width(-1), height(-1) {};
1156 ExtrusionPathFragment(double mm3_per_mm, float width, float height) : mm3_per_mm(mm3_per_mm), width(width), height(height) {};
1157
1158 Polylines polylines;
1159 double mm3_per_mm;
1160 float width;
1161 float height;
1162 };
1163
1164 // Split the extrusions by the overlapping layers, reduce their extrusion rate.
1165 // The last path_fragment is from this_layer.
1166 std::vector<ExtrusionPathFragment> path_fragments(
1167 n_overlapping_layers + 1,
1168 ExtrusionPathFragment(extrusion_path_template->mm3_per_mm, extrusion_path_template->width, extrusion_path_template->height));
1169 // Don't use it, it will be released.
1170 extrusion_path_template = nullptr;
1171
1172#ifdef SLIC3R_DEBUG
1173 static int iRun = 0;
1174 ++ iRun;
1175 BoundingBox bbox;
1176 for (size_t i_overlapping_layer = 0; i_overlapping_layer < n_overlapping_layers; ++ i_overlapping_layer) {
1177 const SupportGeneratorLayer &overlapping_layer = *overlapping_layers[i_overlapping_layer];
1178 bbox.merge(get_extents(overlapping_layer.polygons));
1179 }
1180 for (ExtrusionEntitiesPtr::const_iterator it = extrusions_in_out.begin(); it != extrusions_in_out.end(); ++ it) {
1181 ExtrusionPath *path = dynamic_cast<ExtrusionPath*>(*it);
1182 assert(path != nullptr);
1183 bbox.merge(get_extents(path->polyline));
1184 }
1185 SVG svg(debug_out_path("support-fragments-%d-%lf.svg", iRun, this_layer.print_z).c_str(), bbox);
1186 const float transparency = 0.5f;
1187 // Filled polygons for the overlapping regions.
1188 svg.draw(union_ex(this_layer.polygons), dbg_index_to_color(-1), transparency);
1189 for (size_t i_overlapping_layer = 0; i_overlapping_layer < n_overlapping_layers; ++ i_overlapping_layer) {
1190 const SupportGeneratorLayer &overlapping_layer = *overlapping_layers[i_overlapping_layer];
1191 svg.draw(union_ex(overlapping_layer.polygons), dbg_index_to_color(int(i_overlapping_layer)), transparency);
1192 }
1193 // Contours of the overlapping regions.
1194 svg.draw(to_polylines(this_layer.polygons), dbg_index_to_color(-1), scale_(0.2));
1195 for (size_t i_overlapping_layer = 0; i_overlapping_layer < n_overlapping_layers; ++ i_overlapping_layer) {
1196 const SupportGeneratorLayer &overlapping_layer = *overlapping_layers[i_overlapping_layer];
1197 svg.draw(to_polylines(overlapping_layer.polygons), dbg_index_to_color(int(i_overlapping_layer)), scale_(0.1));
1198 }
1199 // Fill extrusion, the source.
1200 for (ExtrusionEntitiesPtr::const_iterator it = extrusions_in_out.begin(); it != extrusions_in_out.end(); ++ it) {
1201 ExtrusionPath *path = dynamic_cast<ExtrusionPath*>(*it);
1202 std::string color_name;
1203 switch ((it - extrusions_in_out.begin()) % 9) {
1204 case 0: color_name = "magenta"; break;
1205 case 1: color_name = "deepskyblue"; break;
1206 case 2: color_name = "coral"; break;
1207 case 3: color_name = "goldenrod"; break;
1208 case 4: color_name = "orange"; break;
1209 case 5: color_name = "olivedrab"; break;
1210 case 6: color_name = "blueviolet"; break;
1211 case 7: color_name = "brown"; break;
1212 default: color_name = "orchid"; break;
1213 }
1214 svg.draw(path->polyline, color_name, scale_(0.2));
1215 }
1216#endif /* SLIC3R_DEBUG */
1217
1218 // End points of the original paths.
1219 std::vector<std::pair<Point, Point>> path_ends;
1220 // Collect the paths of this_layer.
1221 {
1222 Polylines &polylines = path_fragments.back().polylines;
1223 for (ExtrusionEntity *ee : extrusions_in_out) {
1224 ExtrusionPath *path = dynamic_cast<ExtrusionPath*>(ee);
1225 assert(path != nullptr);
1226 polylines.emplace_back(Polyline(std::move(path->polyline)));
1227 path_ends.emplace_back(std::pair<Point, Point>(polylines.back().points.front(), polylines.back().points.back()));
1228 delete path;
1229 }
1230 }
1231 // Destroy the original extrusion paths, their polylines were moved to path_fragments already.
1232 // This will be the destination for the new paths.
1233 extrusions_in_out.clear();
1234
1235 // Fragment the path segments by overlapping layers. The overlapping layers are sorted by an increasing print_z.
1236 // Trim by the highest overlapping layer first.
1237 for (int i_overlapping_layer = int(n_overlapping_layers) - 1; i_overlapping_layer >= 0; -- i_overlapping_layer) {
1238 const SupportGeneratorLayer &overlapping_layer = *overlapping_layers[i_overlapping_layer];
1239 ExtrusionPathFragment &frag = path_fragments[i_overlapping_layer];
1240 Polygons polygons_trimming = offset(union_ex(overlapping_layer.polygons), float(scale_(0.5*extrusion_width)));
1241 frag.polylines = intersection_pl(path_fragments.back().polylines, polygons_trimming);
1242 path_fragments.back().polylines = diff_pl(path_fragments.back().polylines, polygons_trimming);
1243 // Adjust the extrusion parameters for a reduced layer height and a non-bridging flow (nozzle_dmr = -1, does not matter).
1244 assert(this_layer.print_z > overlapping_layer.print_z);
1245 frag.height = float(this_layer.print_z - overlapping_layer.print_z);
1246 frag.mm3_per_mm = Flow(frag.width, frag.height, -1.f).mm3_per_mm();
1247#ifdef SLIC3R_DEBUG
1248 svg.draw(frag.polylines, dbg_index_to_color(i_overlapping_layer), scale_(0.1));
1249#endif /* SLIC3R_DEBUG */
1250 }
1251
1252#ifdef SLIC3R_DEBUG
1253 svg.draw(path_fragments.back().polylines, dbg_index_to_color(-1), scale_(0.1));
1254 svg.Close();
1255#endif /* SLIC3R_DEBUG */
1256
1257 // Now chain the split segments using hashing and a nearly exact match, maintaining the order of segments.
1258 // Create a single ExtrusionPath or ExtrusionEntityCollection per source ExtrusionPath.
1259 // Map of fragment start/end points to a pair of <i_overlapping_layer, i_polyline_in_layer>
1260 // Because a non-exact matching is used for the end points, a multi-map is used.
1261 // As the clipper library may reverse the order of some clipped paths, store both ends into the map.
1262 struct ExtrusionPathFragmentEnd
1263 {
1264 ExtrusionPathFragmentEnd(size_t alayer_idx, size_t apolyline_idx, bool ais_start) :
1265 layer_idx(alayer_idx), polyline_idx(apolyline_idx), is_start(ais_start) {}
1266 size_t layer_idx;
1267 size_t polyline_idx;
1268 bool is_start;
1269 };
1270 class ExtrusionPathFragmentEndPointAccessor {
1271 public:
1272 ExtrusionPathFragmentEndPointAccessor(const std::vector<ExtrusionPathFragment> &path_fragments) : m_path_fragments(path_fragments) {}
1273 // Return an end point of a fragment, or nullptr if the fragment has been consumed already.
1274 const Point* operator()(const ExtrusionPathFragmentEnd &fragment_end) const {
1275 const Polyline &polyline = m_path_fragments[fragment_end.layer_idx].polylines[fragment_end.polyline_idx];
1276 return polyline.points.empty() ? nullptr :
1277 (fragment_end.is_start ? &polyline.points.front() : &polyline.points.back());
1278 }
1279 private:
1280 ExtrusionPathFragmentEndPointAccessor& operator=(const ExtrusionPathFragmentEndPointAccessor&) {
1281 return *this;
1282 }
1283
1284 const std::vector<ExtrusionPathFragment> &m_path_fragments;
1285 };
1286 const coord_t search_radius = 7;
1287 ClosestPointInRadiusLookup<ExtrusionPathFragmentEnd, ExtrusionPathFragmentEndPointAccessor> map_fragment_starts(
1288 search_radius, ExtrusionPathFragmentEndPointAccessor(path_fragments));
1289 for (size_t i_overlapping_layer = 0; i_overlapping_layer <= n_overlapping_layers; ++ i_overlapping_layer) {
1290 const Polylines &polylines = path_fragments[i_overlapping_layer].polylines;
1291 for (size_t i_polyline = 0; i_polyline < polylines.size(); ++ i_polyline) {
1292 // Map a starting point of a polyline to a pair of <layer, polyline>
1293 if (polylines[i_polyline].points.size() >= 2) {
1294 map_fragment_starts.insert(ExtrusionPathFragmentEnd(i_overlapping_layer, i_polyline, true));
1295 map_fragment_starts.insert(ExtrusionPathFragmentEnd(i_overlapping_layer, i_polyline, false));
1296 }
1297 }
1298 }
1299
1300 // For each source path:
1301 for (size_t i_path = 0; i_path < path_ends.size(); ++ i_path) {
1302 const Point &pt_start = path_ends[i_path].first;
1303 const Point &pt_end = path_ends[i_path].second;
1304 Point pt_current = pt_start;
1305 // Find a chain of fragments with the original / reduced print height.
1306 ExtrusionMultiPath multipath;
1307 for (;;) {
1308 // Find a closest end point to pt_current.
1309 std::pair<const ExtrusionPathFragmentEnd*, coordf_t> end_and_dist2 = map_fragment_starts.find(pt_current);
1310 // There may be a bug in Clipper flipping the order of two last points in a fragment?
1311 // assert(end_and_dist2.first != nullptr);
1312 assert(end_and_dist2.first == nullptr || end_and_dist2.second < search_radius * search_radius);
1313 if (end_and_dist2.first == nullptr) {
1314 // New fragment connecting to pt_current was not found.
1315 // Verify that the last point found is close to the original end point of the unfragmented path.
1316 //const double d2 = (pt_end - pt_current).cast<double>.squaredNorm();
1317 //assert(d2 < coordf_t(search_radius * search_radius));
1318 // End of the path.
1319 break;
1320 }
1321 const ExtrusionPathFragmentEnd &fragment_end_min = *end_and_dist2.first;
1322 // Fragment to consume.
1323 ExtrusionPathFragment &frag = path_fragments[fragment_end_min.layer_idx];
1324 Polyline &frag_polyline = frag.polylines[fragment_end_min.polyline_idx];
1325 // Path to append the fragment to.
1326 ExtrusionPath *path = multipath.paths.empty() ? nullptr : &multipath.paths.back();
1327 if (path != nullptr) {
1328 // Verify whether the path is compatible with the current fragment.
1329 assert(this_layer.layer_type == SupporLayerType::BottomContact || path->height != frag.height || path->mm3_per_mm != frag.mm3_per_mm);
1330 if (path->height != frag.height || path->mm3_per_mm != frag.mm3_per_mm) {
1331 path = nullptr;
1332 }
1333 // Merging with the previous path. This can only happen if the current layer was reduced by a base layer, which was split into a base and interface layer.
1334 }
1335 if (path == nullptr) {
1336 // Allocate a new path.
1337 multipath.paths.push_back(ExtrusionPath(extrusion_role, frag.mm3_per_mm, frag.width, frag.height));
1338 path = &multipath.paths.back();
1339 }
1340 // The Clipper library may flip the order of the clipped polylines arbitrarily.
1341 // Reverse the source polyline, if connecting to the end.
1342 if (! fragment_end_min.is_start)
1343 frag_polyline.reverse();
1344 // Enforce exact overlap of the end points of successive fragments.
1345 assert(frag_polyline.points.front() == pt_current);
1346 frag_polyline.points.front() = pt_current;
1347 // Don't repeat the first point.
1348 if (! path->polyline.points.empty())
1349 path->polyline.points.pop_back();
1350 // Consume the fragment's polyline, remove it from the input fragments, so it will be ignored the next time.
1351 path->polyline.append(std::move(frag_polyline));
1352 frag_polyline.points.clear();
1353 pt_current = path->polyline.points.back();
1354 if (pt_current == pt_end) {
1355 // End of the path.
1356 break;
1357 }
1358 }
1359 if (!multipath.paths.empty()) {
1360 if (multipath.paths.size() == 1) {
1361 // This path was not fragmented.
1362 extrusions_in_out.push_back(new ExtrusionPath(std::move(multipath.paths.front())));
1363 } else {
1364 // This path was fragmented. Copy the collection as a whole object, so the order inside the collection will not be changed
1365 // during the chaining of extrusions_in_out.
1366 extrusions_in_out.push_back(new ExtrusionMultiPath(std::move(multipath)));
1367 }
1368 }
1369 }
1370 // If there are any non-consumed fragments, add them separately.
1371 //FIXME this shall not happen, if the Clipper works as expected and all paths split to fragments could be re-connected.
1372 for (auto it_fragment = path_fragments.begin(); it_fragment != path_fragments.end(); ++ it_fragment)
1373 extrusion_entities_append_paths(extrusions_in_out, std::move(it_fragment->polylines), extrusion_role, it_fragment->mm3_per_mm, it_fragment->width, it_fragment->height);
1374}
Definition ExtrusionEntity.hpp:61
float width
Definition ExtrusionEntity.hpp:67
double mm3_per_mm
Definition ExtrusionEntity.hpp:65
float height
Definition ExtrusionEntity.hpp:69
ExtrusionRole role() const override
Definition ExtrusionEntity.hpp:100
std::string debug_out_path(const char *name,...)
Definition utils.cpp:218
Slic3r::Polylines diff_pl(const Slic3r::Polyline &subject, const Slic3r::Polygons &clip)
Definition ClipperUtils.cpp:852
void extrusion_entities_append_paths(ExtrusionEntitiesPtr &dst, const Polylines &polylines, ExtrusionRole role, double mm3_per_mm, float width, float height, bool can_reverse=true)
Definition ExtrusionEntity.hpp:286
Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::Polygon &clip)
Definition ClipperUtils.cpp:866

References Slic3r::Polyline::append(), Slic3r::SVG::Close(), Slic3r::debug_out_path(), Slic3r::diff_pl(), Slic3r::SVG::draw(), Slic3r::extrusion_entities_append_paths(), Slic3r::ClosestPointInRadiusLookup< ValueType, PointAccessor >::find(), Slic3r::get_extents(), Slic3r::ExtrusionPath::height, Slic3r::ClosestPointInRadiusLookup< ValueType, PointAccessor >::insert(), Slic3r::intersection_pl(), Slic3r::FFFSupport::SupportGeneratorLayer::layer_type, Slic3r::BoundingBoxBase< PointType, APointsType >::merge(), Slic3r::ExtrusionPath::mm3_per_mm, Slic3r::Flow::mm3_per_mm(), modulate_extrusion_by_overlapping_layers(), Slic3r::ExtrusionMultiPath::paths, Slic3r::MultiPoint::points, Slic3r::FFFSupport::SupportGeneratorLayer::polygons, Slic3r::ExtrusionPath::polyline, Slic3r::FFFSupport::SupportGeneratorLayer::print_z, Slic3r::MultiPoint::reverse(), Slic3r::ExtrusionPath::role(), scale_, Slic3r::to_polylines(), Slic3r::union_ex(), and Slic3r::ExtrusionPath::width.

Referenced by modulate_extrusion_by_overlapping_layers().

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

◆ remove_bridges_from_contacts()

void Slic3r::FFFSupport::remove_bridges_from_contacts ( const PrintConfig &  print_config,
const Layer lower_layer,
const LayerRegion layerm,
float  fw,
Polygons contact_polygons 
)
49{
50 // compute the area of bridging perimeters
51 Polygons bridges;
52 {
53 // Surface supporting this layer, expanded by 0.5 * nozzle_diameter, as we consider this kind of overhang to be sufficiently supported.
54 Polygons lower_grown_slices = expand(lower_layer.lslices,
55 //FIXME to mimic the decision in the perimeter generator, we should use half the external perimeter width.
56 0.5f * float(scale_(print_config.nozzle_diameter.get_at(layerm.region().config().perimeter_extruder-1))),
58 // Collect perimeters of this layer.
59 //FIXME split_at_first_point() could split a bridge mid-way
60 #if 0
61 Polylines overhang_perimeters = layerm.perimeters.as_polylines();
62 // workaround for Clipper bug, see Slic3r::Polygon::clip_as_polyline()
63 for (Polyline &polyline : overhang_perimeters)
64 polyline.points[0].x += 1;
65 // Trim the perimeters of this layer by the lower layer to get the unsupported pieces of perimeters.
66 overhang_perimeters = diff_pl(overhang_perimeters, lower_grown_slices);
67 #else
68 Polylines overhang_perimeters = diff_pl(layerm.perimeters().as_polylines(), lower_grown_slices);
69 #endif
70
71 // only consider straight overhangs
72 // only consider overhangs having endpoints inside layer's slices
73 // convert bridging polylines into polygons by inflating them with their thickness
74 // since we're dealing with bridges, we can't assume width is larger than spacing,
75 // so we take the largest value and also apply safety offset to be ensure no gaps
76 // are left in between
77 Flow perimeter_bridge_flow = layerm.bridging_flow(frPerimeter);
78 //FIXME one may want to use a maximum of bridging flow width and normal flow width, as the perimeters are calculated using the normal flow
79 // and then turned to bridging flow, thus their centerlines are derived from non-bridging flow and expanding them by a bridging flow
80 // may not expand them to the edge of their respective islands.
81 const float w = float(0.5 * std::max(perimeter_bridge_flow.scaled_width(), perimeter_bridge_flow.scaled_spacing())) + scaled<float>(0.001);
82 for (Polyline &polyline : overhang_perimeters)
83 if (polyline.is_straight()) {
84 // This is a bridge
85 polyline.extend_start(fw);
86 polyline.extend_end(fw);
87 // Is the straight perimeter segment supported at both sides?
88 Point pts[2] = { polyline.first_point(), polyline.last_point() };
89 bool supported[2] = { false, false };
90 for (size_t i = 0; i < lower_layer.lslices.size() && ! (supported[0] && supported[1]); ++ i)
91 for (int j = 0; j < 2; ++ j)
92 if (! supported[j] && lower_layer.lslices_ex[i].bbox.contains(pts[j]) && lower_layer.lslices[i].contains(pts[j]))
93 supported[j] = true;
94 if (supported[0] && supported[1])
95 // Offset a polyline into a thick line.
96 polygons_append(bridges, offset(polyline, w));
97 }
98 bridges = union_(bridges);
99 }
100 // remove the entire bridges and only support the unsupported edges
101 //FIXME the brided regions are already collected as layerm.bridged. Use it?
102 for (const Surface &surface : layerm.fill_surfaces())
103 if (surface.surface_type == stBottomBridge && surface.bridge_angle >= 0.0)
104 polygons_append(bridges, surface.expolygon);
105 //FIXME add the gap filled areas. Extrude the gaps with a bridge flow?
106 // Remove the unsupported ends of the bridges from the bridged areas.
107 //FIXME add supports at regular intervals to support long bridges!
108 bridges = diff(bridges,
109 // Offset unsupported edges into polygons.
111 // Remove bridged areas from the supported areas.
112 contact_polygons = diff(contact_polygons, bridges, ApplySafetyOffset::Yes);
113
114 #ifdef SLIC3R_DEBUG
115 static int iRun = 0;
116 SVG::export_expolygons(debug_out_path("support-top-contacts-remove-bridges-run%d.svg", iRun ++),
117 { { { union_ex(offset(layerm.unsupported_bridge_edges(), scale_(SUPPORT_MATERIAL_MARGIN), SUPPORT_SURFACES_OFFSET_PARAMETERS)) }, { "unsupported_bridge_edges", "orange", 0.5f } },
118 { { union_ex(contact_polygons) }, { "contact_polygons", "blue", 0.5f } },
119 { { union_ex(bridges) }, { "bridges", "red", "black", "", scaled<coord_t>(0.1f), 0.5f } } });
120 #endif /* SLIC3R_DEBUG */
121}
#define SUPPORT_MATERIAL_MARGIN
Definition SupportCommon.cpp:37
virtual Polylines as_polylines() const
Definition ExtrusionEntity.hpp:53
ExPolygons lslices
Definition Layer.hpp:339
LayerSlices lslices_ex
Definition Layer.hpp:341
Flow bridging_flow(FlowRole role, bool force_thick_bridges=false) const
Definition LayerRegion.cpp:32
const Polylines & unsupported_bridge_edges() const
Definition Layer.hpp:126
const PrintRegion & region() const
Definition Layer.hpp:99
const ExtrusionEntityCollection & perimeters() const
Definition Layer.hpp:130
const PrintRegionConfig & config() const
Definition Print.hpp:87
if(!(yy_init))
Definition lexer.c:1190
bridge_angle((ConfigOptionInt, bottom_solid_layers))((ConfigOptionFloat
@ stBottomBridge
Definition Surface.hpp:15

References Slic3r::ExtrusionEntity::as_polylines(), Slic3r::LayerRegion::bridging_flow(), Slic3r::PrintRegion::config(), Slic3r::debug_out_path(), Slic3r::diff(), Slic3r::diff_pl(), Slic3r::expand(), Slic3r::SVG::export_expolygons(), Slic3r::LayerRegion::fill_surfaces(), Slic3r::frPerimeter, Slic3r::Layer::lslices, Slic3r::Layer::lslices_ex, Slic3r::offset(), Slic3r::LayerRegion::perimeters(), Slic3r::polygons_append(), Slic3r::LayerRegion::region(), scale_, Slic3r::Flow::scaled_spacing(), Slic3r::Flow::scaled_width(), Slic3r::stBottomBridge, SUPPORT_MATERIAL_MARGIN, SUPPORT_SURFACES_OFFSET_PARAMETERS, Slic3r::union_(), Slic3r::union_ex(), Slic3r::LayerRegion::unsupported_bridge_edges(), and Slic3r::Yes.

Referenced by Slic3r::detect_overhangs(), and Slic3r::FFFTreeSupport::generate_overhangs().

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

◆ support_surface_type_to_color_name()

const char * Slic3r::FFFSupport::support_surface_type_to_color_name ( const SupporLayerType  surface_type)
12{
13 switch (surface_type) {
14 case SupporLayerType::TopContact: return "rgb(255,0,0)"; // "red";
15 case SupporLayerType::TopInterface: return "rgb(0,255,0)"; // "green";
16 case SupporLayerType::Base: return "rgb(0,0,255)"; // "blue";
17 case SupporLayerType::BottomInterface:return "rgb(255,255,128)"; // yellow
18 case SupporLayerType::BottomContact: return "rgb(255,0,255)"; // magenta
19 case SupporLayerType::RaftInterface: return "rgb(0,255,255)";
20 case SupporLayerType::RaftBase: return "rgb(128,128,128)";
21 case SupporLayerType::Unknown: return "rgb(128,0,0)"; // maroon
22 default: return "rgb(64,64,64)";
23 };
24}

References Base, BottomContact, BottomInterface, RaftBase, RaftInterface, TopContact, TopInterface, and Unknown.

Referenced by export_print_z_polygons_and_extrusions_to_svg(), export_print_z_polygons_to_svg(), and export_support_surface_type_legend_to_svg().

+ Here is the caller graph for this function:

◆ tree_supports_generate_paths()

static void Slic3r::FFFSupport::tree_supports_generate_paths ( ExtrusionEntitiesPtr dst,
const Polygons polygons,
const Flow flow,
const SupportParameters support_params 
)
inlinestatic
542{
543 // Offset expolygon inside, returns number of expolygons collected (0 or 1).
544 // Vertices of output paths are marked with Z = source contour index of the expoly.
545 // Vertices at the intersection of source contours are marked with Z = -1.
546 auto shrink_expolygon_with_contour_idx = [](const Slic3r::ExPolygon &expoly, const float delta, ClipperLib::JoinType joinType, double miterLimit, ClipperLib_Z::Paths &out) -> int
547 {
548 assert(delta > 0);
549 auto append_paths_with_z = [](ClipperLib::Paths &src, coord_t contour_idx, ClipperLib_Z::Paths &dst) {
550 dst.reserve(next_highest_power_of_2(dst.size() + src.size()));
551 for (const ClipperLib::Path &contour : src) {
552 ClipperLib_Z::Path tmp;
553 tmp.reserve(contour.size());
554 for (const Point &p : contour)
555 tmp.emplace_back(p.x(), p.y(), contour_idx);
556 dst.emplace_back(std::move(tmp));
557 }
558 };
559
560 // 1) Offset the outer contour.
561 ClipperLib_Z::Paths contours;
562 {
564 if (joinType == jtRound)
565 co.ArcTolerance = miterLimit;
566 else
567 co.MiterLimit = miterLimit;
568 co.ShortestEdgeLength = double(delta * 0.005);
570 ClipperLib::Paths contours_raw;
571 co.Execute(contours_raw, - delta);
572 if (contours_raw.empty())
573 // No need to try to offset the holes.
574 return 0;
575 append_paths_with_z(contours_raw, 0, contours);
576 }
577
578 if (expoly.holes.empty()) {
579 // No need to subtract holes from the offsetted expolygon, we are done.
580 append(out, std::move(contours));
581 } else {
582 // 2) Offset the holes one by one, collect the offsetted holes.
583 ClipperLib_Z::Paths holes;
584 {
585 for (const Polygon &hole : expoly.holes) {
587 if (joinType == jtRound)
588 co.ArcTolerance = miterLimit;
589 else
590 co.MiterLimit = miterLimit;
591 co.ShortestEdgeLength = double(delta * 0.005);
594 // Execute reorients the contours so that the outer most contour has a positive area. Thus the output
595 // contours will be CCW oriented even though the input paths are CW oriented.
596 // Offset is applied after contour reorientation, thus the signum of the offset value is reversed.
597 co.Execute(out2, delta);
598 append_paths_with_z(out2, 1 + (&hole - expoly.holes.data()), holes);
599 }
600 }
601
602 // 3) Subtract holes from the contours.
603 if (holes.empty()) {
604 // No hole remaining after an offset. Just copy the outer contour.
605 append(out, std::move(contours));
606 } else {
607 // Negative offset. There is a chance, that the offsetted hole intersects the outer contour.
608 // Subtract the offsetted holes from the offsetted contours.
609 ClipperLib_Z::Clipper clipper;
610 clipper.ZFillFunction([](const ClipperLib_Z::IntPoint &e1bot, const ClipperLib_Z::IntPoint &e1top, const ClipperLib_Z::IntPoint &e2bot, const ClipperLib_Z::IntPoint &e2top, ClipperLib_Z::IntPoint &pt) {
611 //pt.z() = std::max(std::max(e1bot.z(), e1top.z()), std::max(e2bot.z(), e2top.z()));
612 // Just mark the intersection.
613 pt.z() = -1;
614 });
615 clipper.AddPaths(contours, ClipperLib_Z::ptSubject, true);
616 clipper.AddPaths(holes, ClipperLib_Z::ptClip, true);
617 ClipperLib_Z::Paths output;
618 clipper.Execute(ClipperLib_Z::ctDifference, output, ClipperLib_Z::pftNonZero, ClipperLib_Z::pftNonZero);
619 if (! output.empty()) {
620 append(out, std::move(output));
621 } else {
622 // The offsetted holes have eaten up the offsetted outer contour.
623 return 0;
624 }
625 }
626 }
627
628 return 1;
629 };
630
631 const double spacing = flow.scaled_spacing();
632 // Clip the sheath path to avoid the extruder to get exactly on the first point of the loop.
633 const double clip_length = spacing * 0.15;
634 const double anchor_length = spacing * 6.;
635 ClipperLib_Z::Paths anchor_candidates;
636 for (ExPolygon& expoly : closing_ex(polygons, float(SCALED_EPSILON), float(SCALED_EPSILON + 0.5 * flow.scaled_width()))) {
637 std::unique_ptr<ExtrusionEntityCollection> eec;
639 if (double area = expoly.area(); area > support_params.tree_branch_diameter_double_wall_area_scaled) {
640 eec = std::make_unique<ExtrusionEntityCollection>();
641 // Don't reoder internal / external loops of the same island, always start with the internal loop.
642 eec->no_sort = true;
643 // Make the tree branch stable by adding another perimeter.
644 ExPolygons level2 = offset2_ex({ expoly }, -1.5 * flow.scaled_width(), 0.5 * flow.scaled_width());
645 if (level2.size() == 1) {
646 Polylines polylines;
647 extrusion_entities_append_paths(eec->entities, draw_perimeters(expoly, clip_length), ExtrusionRole::SupportMaterial, flow.mm3_per_mm(), flow.width(), flow.height(),
648 // Disable reversal of the path, always start with the anchor, always print CCW.
649 false);
650 expoly = level2.front();
651 }
652 }
653
654 // Try to produce one more perimeter to place the seam anchor.
655 // First genrate a 2nd perimeter loop as a source for anchor candidates.
656 // The anchor candidate points are annotated with an index of the source contour or with -1 if on intersection.
657 anchor_candidates.clear();
658 shrink_expolygon_with_contour_idx(expoly, flow.scaled_width(), DefaultJoinType, 1.2, anchor_candidates);
659 // Orient all contours CW.
660 for (auto &path : anchor_candidates)
661 if (ClipperLib_Z::Area(path) > 0)
662 std::reverse(path.begin(), path.end());
663
664 // Draw the perimeters.
665 Polylines polylines;
666 polylines.reserve(expoly.holes.size() + 1);
667 for (int idx_loop = 0; idx_loop < int(expoly.num_contours()); ++ idx_loop) {
668 // Open the loop with a seam.
669 const Polygon &loop = expoly.contour_or_hole(idx_loop);
670 Polyline pl(loop.points);
671 // Orient all contours CW, because the anchor will be added to the end of polyline while we want to start a loop with the anchor.
672 if (idx_loop == 0)
673 // It is an outer contour.
674 pl.reverse();
675 pl.points.emplace_back(pl.points.front());
676 pl.clip_end(clip_length);
677 if (pl.size() < 2)
678 continue;
679 // Find the foot of the seam point on anchor_candidates. Only pick an anchor point that was created by offsetting the source contour.
680 ClipperLib_Z::Path *closest_contour = nullptr;
681 Vec2d closest_point;
682 int closest_point_idx = -1;
683 double closest_point_t = 0.;
684 double d2min = std::numeric_limits<double>::max();
685 Vec2d seam_pt = pl.back().cast<double>();
686 for (ClipperLib_Z::Path &path : anchor_candidates)
687 for (int i = 0; i < int(path.size()); ++ i) {
688 int j = next_idx_modulo(i, path);
689 if (path[i].z() == idx_loop || path[j].z() == idx_loop) {
690 Vec2d pi(path[i].x(), path[i].y());
691 Vec2d pj(path[j].x(), path[j].y());
692 Vec2d v = pj - pi;
693 Vec2d w = seam_pt - pi;
694 auto l2 = v.squaredNorm();
695 auto t = std::clamp((l2 == 0) ? 0 : v.dot(w) / l2, 0., 1.);
696 if ((path[i].z() == idx_loop || t > EPSILON) && (path[j].z() == idx_loop || t < 1. - EPSILON)) {
697 // Closest point.
698 Vec2d fp = pi + v * t;
699 double d2 = (fp - seam_pt).squaredNorm();
700 if (d2 < d2min) {
701 d2min = d2;
702 closest_contour = &path;
703 closest_point = fp;
704 closest_point_idx = i;
705 closest_point_t = t;
706 }
707 }
708 }
709 }
710 if (d2min < sqr(flow.scaled_width() * 3.)) {
711 // Try to cut an anchor from the closest_contour.
712 // Both closest_contour and pl are CW oriented.
713 pl.points.emplace_back(closest_point.cast<coord_t>());
714 const ClipperLib_Z::Path &path = *closest_contour;
715 double remaining_length = anchor_length - (seam_pt - closest_point).norm();
716 int i = closest_point_idx;
717 int j = next_idx_modulo(i, *closest_contour);
718 Vec2d pi(path[i].x(), path[i].y());
719 Vec2d pj(path[j].x(), path[j].y());
720 Vec2d v = pj - pi;
721 double l = v.norm();
722 if (remaining_length < (1. - closest_point_t) * l) {
723 // Just trim the current line.
724 pl.points.emplace_back((closest_point + v * (remaining_length / l)).cast<coord_t>());
725 } else {
726 // Take the rest of the current line, continue with the other lines.
727 pl.points.emplace_back(path[j].x(), path[j].y());
728 pi = pj;
729 for (i = j; path[i].z() == idx_loop && remaining_length > 0; i = j, pi = pj) {
730 j = next_idx_modulo(i, path);
731 pj = Vec2d(path[j].x(), path[j].y());
732 v = pj - pi;
733 l = v.norm();
734 if (i == closest_point_idx) {
735 // Back at the first segment. Most likely this should not happen and we may end the anchor.
736 break;
737 }
738 if (remaining_length <= l) {
739 pl.points.emplace_back((pi + v * (remaining_length / l)).cast<coord_t>());
740 break;
741 }
742 pl.points.emplace_back(path[j].x(), path[j].y());
743 remaining_length -= l;
744 }
745 }
746 }
747 // Start with the anchor.
748 pl.reverse();
749 polylines.emplace_back(std::move(pl));
750 }
751
752 ExtrusionEntitiesPtr &out = eec ? eec->entities : dst;
753 extrusion_entities_append_paths(out, std::move(polylines), ExtrusionRole::SupportMaterial, flow.mm3_per_mm(), flow.width(), flow.height(),
754 // Disable reversal of the path, always start with the anchor, always print CCW.
755 false);
756 if (eec) {
757 std::reverse(eec->entities.begin(), eec->entities.end());
758 dst.emplace_back(eec.release());
759 }
760 }
761}
Definition clipper.hpp:540
void AddPath(const Path &path, JoinType joinType, EndType endType)
Definition clipper.cpp:3328
double MiterLimit
Definition clipper.hpp:554
double ArcTolerance
Definition clipper.hpp:555
double ShortestEdgeLength
Definition clipper.hpp:556
void Execute(Paths &solution, double delta)
Definition clipper.cpp:3418
size_t num_contours() const
Definition ExPolygon.hpp:80
double area() const
Definition ExPolygon.cpp:52
Polygon & contour_or_hole(size_t idx)
Definition ExPolygon.hpp:81
void clear()
Definition ExPolygon.hpp:38
size_t size() const
Definition MultiPoint.hpp:39
std::vector< IntPoint, Allocator< IntPoint > > Path
Definition clipper.hpp:121
double Area(const Path &poly)
Definition clipper.cpp:151
JoinType
Definition clipper.hpp:138
@ etClosedPolygon
Definition clipper.hpp:139
std::vector< Path, Allocator< Path > > Paths
Definition clipper.hpp:122
const Scalar & y
Definition MathFunctions.h:552
static Polylines draw_perimeters(const ExPolygon &expoly, double clip_length)
Definition SupportCommon.cpp:519
T l2(const boost::geometry::model::d2::point_xy< T > &v)
Definition ExtrusionSimulator.cpp:166
Eigen::Matrix< double, 2, 1, Eigen::DontAlign > Vec2d
Definition Point.hpp:51
std::vector< ExPolygon > ExPolygons
Definition ExPolygon.hpp:13
uint16_t next_highest_power_of_2(uint16_t v)
Definition Utils.hpp:125
INDEX_TYPE next_idx_modulo(INDEX_TYPE idx, const INDEX_TYPE count)
Definition Utils.hpp:203
constexpr T sqr(T x)
Definition libslic3r.h:258
std::vector< ExtrusionEntity * > ExtrusionEntitiesPtr
Definition ExtrusionEntity.hpp:58
ExPolygons offset2_ex(const ExPolygons &expolygons, const float delta1, const float delta2, ClipperLib::JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:576
const double pi
Definition agg_basics.h:268
IGL_INLINE void loop(const int n_verts, const Eigen::PlainObjectBase< DerivedF > &F, Eigen::SparseMatrix< SType > &S, Eigen::PlainObjectBase< DerivedNF > &NF)
Definition loop.cpp:21
IGL_INLINE double dot(const double *a, const double *b)
Definition dot.cpp:11
TCoord< P > x(const P &p)
Definition geometry_traits.hpp:297
S::iterator begin(S &sh, const PathTag &)
Definition geometry_traits.hpp:614
Unit area(const Cntr &poly, const PathTag &)
Definition geometry_traits.hpp:971
S::iterator end(S &sh, const PathTag &)
Definition geometry_traits.hpp:620
Slic3r::Polygon & hole(Slic3r::ExPolygon &sh, unsigned long idx)
Definition geometries.hpp:200
const THolesContainer< PolygonImpl > & holes(const Slic3r::ExPolygon &sh)
Definition geometries.hpp:189
void append(SurfaceCut &sc, SurfaceCut &&sc_add)
Merge two surface cuts together Added surface cut will be consumed.
Definition CutSurface.cpp:3550
Slic3r::Polygon Polygon
Definition Emboss.cpp:34
double tree_branch_diameter_double_wall_area_scaled
Definition SupportParameters.hpp:81

References ClipperLib::ClipperOffset::AddPath(), ClipperLib::ClipperOffset::ArcTolerance, Slic3r::ExPolygon::area(), Slic3r::MultiPoint::back(), Slic3r::ExPolygon::clear(), Slic3r::Polyline::clip_end(), Slic3r::closing_ex(), Slic3r::ExPolygon::contour, Slic3r::ExPolygon::contour_or_hole(), draw_perimeters(), EPSILON, ClipperLib::etClosedPolygon, ClipperLib::ClipperOffset::Execute(), Slic3r::extrusion_entities_append_paths(), Slic3r::Flow::height(), Slic3r::ExPolygon::holes, Slic3r::l2(), ClipperLib::ClipperOffset::MiterLimit, Slic3r::Flow::mm3_per_mm(), Slic3r::next_highest_power_of_2(), Slic3r::next_idx_modulo(), Slic3r::ExPolygon::num_contours(), Slic3r::offset2_ex(), Slic3r::MultiPoint::points, Slic3r::MultiPoint::reverse(), SCALED_EPSILON, Slic3r::Flow::scaled_spacing(), Slic3r::Flow::scaled_width(), ClipperLib::ClipperOffset::ShortestEdgeLength, Slic3r::MultiPoint::size(), Slic3r::sqr(), Slic3r::FFFSupport::SupportParameters::tree_branch_diameter_double_wall_area_scaled, tree_supports_generate_paths(), and Slic3r::Flow::width().

Referenced by generate_support_toolpaths(), and tree_supports_generate_paths().

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

Variable Documentation

◆ support_types_interface

constexpr const std::initializer_list<SupporLayerType> Slic3r::FFFSupport::support_types_interface
staticconstexpr
Initial value:
{
SupporLayerType::RaftInterface, SupporLayerType::BottomContact, SupporLayerType::BottomInterface, SupporLayerType::TopContact, SupporLayerType::TopInterface
}

Referenced by generate_support_layers().