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

#include <src/libslic3r/Layer.hpp>

+ Inheritance diagram for Slic3r::SupportLayer:
+ Collaboration diagram for Slic3r::SupportLayer:

Public Member Functions

virtual bool has_extrusions () const
 
size_t interface_id () const
 
size_t id () const
 
void set_id (size_t id)
 
PrintObjectobject ()
 
const PrintObjectobject () const
 
coordf_t bottom_z () const
 
size_t region_count () const
 
const LayerRegionget_region (int idx) const
 
LayerRegionget_region (int idx)
 
LayerRegionadd_region (const PrintRegion *print_region)
 
const LayerRegionPtrsregions () const
 
bool empty () const
 
void make_slices ()
 
void backup_untyped_slices ()
 
void restore_untyped_slices ()
 
void restore_untyped_slices_no_extra_perimeters ()
 
ExPolygons merged (float offset) const
 
template<class T >
bool any_internal_region_slice_contains (const T &item) const
 
template<class T >
bool any_bottom_region_slice_contains (const T &item) const
 
void make_perimeters ()
 
void make_fills ()
 
void make_fills (FillAdaptive::Octree *adaptive_fill_octree, FillAdaptive::Octree *support_fill_octree, FillLightning::Generator *lightning_generator)
 
Polylines generate_sparse_infill_polylines_for_anchoring (FillAdaptive::Octree *adaptive_fill_octree, FillAdaptive::Octree *support_fill_octree, FillLightning::Generator *lightning_generator) const
 
void make_ironing ()
 
void export_region_slices_to_svg (const char *path) const
 
void export_region_fill_surfaces_to_svg (const char *path) const
 
void export_region_slices_to_svg_debug (const char *name) const
 
void export_region_fill_surfaces_to_svg_debug (const char *name) const
 

Static Public Member Functions

static void build_up_down_graph (Layer &below, Layer &above)
 

Public Attributes

ExPolygons support_islands
 
BoundingBoxes support_islands_bboxes
 
ExtrusionEntityCollection support_fills
 
Layerupper_layer
 
Layerlower_layer
 
coordf_t slice_z
 
coordf_t print_z
 
coordf_t height
 
CurledLines curled_lines
 
ExPolygons lslices
 
std::vector< size_t > lslice_indices_sorted_by_print_order
 
LayerSlices lslices_ex
 

Protected Member Functions

 SupportLayer (size_t id, size_t interface_id, PrintObject *object, coordf_t height, coordf_t print_z, coordf_t slice_z)
 
virtual ~SupportLayer ()=default
 
void clear_fills ()
 

Protected Attributes

size_t m_interface_id
 

Private Member Functions

void sort_perimeters_into_islands (const SurfaceCollection &slices, const uint32_t region_id, const std::vector< std::pair< ExtrusionRange, ExtrusionRange > > &perimeter_and_gapfill_ranges, ExPolygons &&fill_expolygons, const std::vector< ExPolygonRange > &fill_expolygons_ranges, const std::vector< uint32_t > &layer_region_ids)
 

Private Attributes

size_t m_id
 
PrintObjectm_object
 
LayerRegionPtrs m_regions
 

Friends

class PrintObject
 

Detailed Description

Constructor & Destructor Documentation

◆ SupportLayer()

Slic3r::SupportLayer::SupportLayer ( size_t  id,
size_t  interface_id,
PrintObject object,
coordf_t  height,
coordf_t  print_z,
coordf_t  slice_z 
)
inlineprotected
450 :
coordf_t slice_z
Definition Layer.hpp:323
coordf_t height
Definition Layer.hpp:325
Layer(size_t id, PrintObject *object, coordf_t height, coordf_t print_z, coordf_t slice_z)
Definition Layer.hpp:395
coordf_t print_z
Definition Layer.hpp:324
size_t m_interface_id
Definition Layer.hpp:454
size_t interface_id() const
Definition Layer.hpp:443

◆ ~SupportLayer()

virtual Slic3r::SupportLayer::~SupportLayer ( )
protectedvirtualdefault

Member Function Documentation

◆ add_region()

LayerRegion * Slic3r::Layer::add_region ( const PrintRegion print_region)
inherited
36{
37 m_regions.emplace_back(new LayerRegion(this, print_region));
38 return m_regions.back();
39}
LayerRegionPtrs m_regions
Definition Layer.hpp:424

References Slic3r::Layer::m_regions.

◆ any_bottom_region_slice_contains()

template<class T >
bool Slic3r::Layer::any_bottom_region_slice_contains ( const T &  item) const
inlineinherited
365 {
366 for (const LayerRegion *layerm : m_regions) if (layerm->slices().any_bottom_contains(item)) return true;
367 return false;
368 }
if(!(yy_init))
Definition lexer.c:1190

References Slic3r::Layer::m_regions.

◆ any_internal_region_slice_contains()

template<class T >
bool Slic3r::Layer::any_internal_region_slice_contains ( const T &  item) const
inlineinherited
361 {
362 for (const LayerRegion *layerm : m_regions) if (layerm->slices().any_internal_contains(item)) return true;
363 return false;
364 }

References Slic3r::Layer::m_regions.

◆ backup_untyped_slices()

void Slic3r::Layer::backup_untyped_slices ( )
inherited
549{
550 if (layer_needs_raw_backup(this)) {
551 for (LayerRegion *layerm : m_regions)
552 layerm->m_raw_slices = to_expolygons(layerm->slices().surfaces);
553 } else {
554 assert(m_regions.size() == 1);
555 m_regions.front()->m_raw_slices.clear();
556 }
557}
static bool layer_needs_raw_backup(const Layer *layer)
Definition Layer.cpp:543
ExPolygons to_expolygons(const Polygons &polys)
Definition ExPolygon.hpp:347

References Slic3r::layer_needs_raw_backup(), and Slic3r::to_expolygons().

+ Here is the call graph for this function:

◆ bottom_z()

coordf_t Slic3r::Layer::bottom_z ( ) const
inlineinherited
326{ return this->print_z - this->height; }

References Slic3r::Layer::height.

Referenced by Slic3r::SupportSpotsGenerator::check_stability(), Slic3r::PrintObject::discover_vertical_shells(), and Slic3r::new_contact_layer().

+ Here is the caller graph for this function:

◆ build_up_down_graph()

void Slic3r::Layer::build_up_down_graph ( Layer below,
Layer above 
)
staticinherited
518{
519 coord_t paths_below_offset = 0;
520 ClipperLib_Z::Paths paths_below = expolygons_to_zpaths_shrunk(below.lslices, paths_below_offset);
521 coord_t paths_above_offset = paths_below_offset + coord_t(below.lslices.size());
522 ClipperLib_Z::Paths paths_above = expolygons_to_zpaths_shrunk(above.lslices, paths_above_offset);
523#ifndef NDEBUG
524 coord_t paths_end = paths_above_offset + coord_t(above.lslices.size());
525#endif // NDEBUG
526
527 ClipperLib_Z::Clipper clipper;
528 ClipperLib_Z::PolyTree result;
530 ClipperZUtils::ClipperZIntersectionVisitor visitor(intersections);
531 clipper.ZFillFunction(visitor.clipper_callback());
532 clipper.AddPaths(paths_below, ClipperLib_Z::ptSubject, true);
533 clipper.AddPaths(paths_above, ClipperLib_Z::ptClip, true);
534 clipper.Execute(ClipperLib_Z::ctIntersection, result, ClipperLib_Z::pftNonZero, ClipperLib_Z::pftNonZero);
535
536 connect_layer_slices(below, above, result, intersections, paths_below_offset, paths_above_offset
537#ifndef NDEBUG
538 , paths_end
539#endif // NDEBUG
540 );
541}
std::vector< Intersection > Intersections
Definition ClipperZUtils.hpp:106
int32_t coord_t
Definition libslic3r.h:39
static ClipperLib_Z::Paths expolygons_to_zpaths_shrunk(const ExPolygons &expolygons, coord_t isrc)
Definition Layer.cpp:66
static void connect_layer_slices(Layer &below, Layer &above, const ClipperLib_Z::PolyTree &polytree, const std::vector< std::pair< coord_t, coord_t > > &intersections, const coord_t offset_below, const coord_t offset_above, const coord_t offset_end)
Definition Layer.cpp:165

References Slic3r::ClipperZUtils::ClipperZIntersectionVisitor::clipper_callback(), Slic3r::connect_layer_slices(), Slic3r::expolygons_to_zpaths_shrunk(), and Slic3r::Layer::lslices.

+ Here is the call graph for this function:

◆ clear_fills()

void Slic3r::Layer::clear_fills ( )
protectedinherited
428{
429 for (LayerRegion *layerm : m_regions)
430 layerm->m_fills.clear();
431 for (LayerSlice &lslice : lslices_ex)
432 for (LayerIsland &island : lslice.islands)
433 island.fills.clear();
434}
LayerSlices lslices_ex
Definition Layer.hpp:341

◆ empty()

bool Slic3r::Layer::empty ( ) const
inherited
27{
28 for (const LayerRegion *layerm : m_regions)
29 if (layerm != nullptr && ! layerm->slices().empty())
30 // Non empty layer.
31 return false;
32 return true;
33}
bool empty() const
Definition Layer.cpp:26

References Slic3r::Layer::m_regions.

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

+ Here is the caller graph for this function:

◆ export_region_fill_surfaces_to_svg()

void Slic3r::Layer::export_region_fill_surfaces_to_svg ( const char *  path) const
inherited
1073{
1074 BoundingBox bbox;
1075 for (const auto *region : m_regions)
1076 for (const auto &surface : region->slices())
1077 bbox.merge(get_extents(surface.expolygon));
1079 Point legend_pos(bbox.min(0), bbox.max(1));
1080 bbox.merge(Point(std::max(bbox.min(0) + legend_size(0), bbox.max(0)), bbox.max(1) + legend_size(1)));
1081
1082 SVG svg(path, bbox);
1083 const float transparency = 0.5f;
1084 for (const auto *region : m_regions)
1085 for (const auto &surface : region->slices())
1086 svg.draw(surface.expolygon, surface_type_to_color_name(surface.surface_type), transparency);
1087 export_surface_type_legend_to_svg(svg, legend_pos);
1088 svg.Close();
1089}
#define const
Definition getopt.c:38
void draw(const IconManager::Icon &icon, const ImVec2 &size, const ImVec4 &tint_col, const ImVec4 &border_col)
Draw imgui image with icon.
Definition IconManager.cpp:164
BoundingBox get_extents(const ExPolygon &expolygon)
Definition ExPolygon.cpp:352
const char * surface_type_to_color_name(const SurfaceType surface_type)
Definition Surface.cpp:34
void export_surface_type_legend_to_svg(SVG &svg, const Point &pos)
Definition Surface.cpp:54
Point export_surface_type_legend_to_svg_box_size()
Definition Surface.cpp:49
TMultiShape< PolygonImpl > merge(const TMultiShape< PolygonImpl > &shapes)
Definition geometries.hpp:259
Kernel::Point_2 Point
Definition point_areas.cpp:20

References Slic3r::SVG::Close(), Slic3r::SVG::draw(), Slic3r::export_surface_type_legend_to_svg(), Slic3r::export_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, and Slic3r::surface_type_to_color_name().

+ Here is the call graph for this function:

◆ export_region_fill_surfaces_to_svg_debug()

void Slic3r::Layer::export_region_fill_surfaces_to_svg_debug ( const char *  name) const
inherited
1093{
1094 static size_t idx = 0;
1095 this->export_region_fill_surfaces_to_svg(debug_out_path("Layer-fill_surfaces-%s-%d.svg", name, idx ++).c_str());
1096}
void export_region_fill_surfaces_to_svg(const char *path) const
Definition Layer.cpp:1072
std::string debug_out_path(const char *name,...)
Definition utils.cpp:218

References Slic3r::debug_out_path().

+ Here is the call graph for this function:

◆ export_region_slices_to_svg()

void Slic3r::Layer::export_region_slices_to_svg ( const char *  path) const
inherited
1047{
1048 BoundingBox bbox;
1049 for (const auto *region : m_regions)
1050 for (const auto &surface : region->slices())
1051 bbox.merge(get_extents(surface.expolygon));
1053 Point legend_pos(bbox.min(0), bbox.max(1));
1054 bbox.merge(Point(std::max(bbox.min(0) + legend_size(0), bbox.max(0)), bbox.max(1) + legend_size(1)));
1055
1056 SVG svg(path, bbox);
1057 const float transparency = 0.5f;
1058 for (const auto *region : m_regions)
1059 for (const auto &surface : region->slices())
1060 svg.draw(surface.expolygon, surface_type_to_color_name(surface.surface_type), transparency);
1061 export_surface_type_legend_to_svg(svg, legend_pos);
1062 svg.Close();
1063}

References Slic3r::SVG::Close(), Slic3r::SVG::draw(), Slic3r::export_surface_type_legend_to_svg(), Slic3r::export_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, and Slic3r::surface_type_to_color_name().

+ Here is the call graph for this function:

◆ export_region_slices_to_svg_debug()

void Slic3r::Layer::export_region_slices_to_svg_debug ( const char *  name) const
inherited
1067{
1068 static size_t idx = 0;
1069 this->export_region_slices_to_svg(debug_out_path("Layer-slices-%s-%d.svg", name, idx ++).c_str());
1070}
void export_region_slices_to_svg(const char *path) const
Definition Layer.cpp:1046

References Slic3r::debug_out_path().

+ Here is the call graph for this function:

◆ generate_sparse_infill_polylines_for_anchoring()

Polylines Slic3r::Layer::generate_sparse_infill_polylines_for_anchoring ( FillAdaptive::Octree adaptive_fill_octree,
FillAdaptive::Octree support_fill_octree,
FillLightning::Generator lightning_generator 
) const
inherited
609{
610 std::vector<SurfaceFill> surface_fills = group_fills(*this);
611 const Slic3r::BoundingBox bbox = this->object()->bounding_box();
612 const auto resolution = this->object()->print()->config().gcode_resolution.value;
613
614 Polylines sparse_infill_polylines{};
615
616 for (SurfaceFill &surface_fill : surface_fills) {
617 if (surface_fill.surface.surface_type != stInternal) {
618 continue;
619 }
620
621 switch (surface_fill.params.pattern) {
622 case ipCount: continue; break;
623 case ipSupportBase: continue; break;
624 case ipEnsuring: continue; break;
625 case ipLightning:
626 case ipAdaptiveCubic:
627 case ipSupportCubic:
628 case ipRectilinear:
629 case ipMonotonic:
630 case ipMonotonicLines:
632 case ipGrid:
633 case ipTriangles:
634 case ipStars:
635 case ipCubic:
636 case ipLine:
637 case ipConcentric:
638 case ipHoneycomb:
639 case ip3DHoneycomb:
640 case ipGyroid:
641 case ipHilbertCurve:
643 case ipOctagramSpiral: break;
644 }
645
646 // Create the filler object.
647 std::unique_ptr<Fill> f = std::unique_ptr<Fill>(Fill::new_from_type(surface_fill.params.pattern));
648 f->set_bounding_box(bbox);
649 f->layer_id = this->id() - this->object()->get_layer(0)->id(); // We need to subtract raft layers.
650 f->z = this->print_z;
651 f->angle = surface_fill.params.angle;
652 f->adapt_fill_octree = (surface_fill.params.pattern == ipSupportCubic) ? support_fill_octree : adaptive_fill_octree;
653 f->print_config = &this->object()->print()->config();
654 f->print_object_config = &this->object()->config();
655
656 if (surface_fill.params.pattern == ipLightning)
657 dynamic_cast<FillLightning::Filler *>(f.get())->generator = lightning_generator;
658
659 // calculate flow spacing for infill pattern generation
660 double link_max_length = 0.;
661 if (!surface_fill.params.bridge) {
662#if 0
663 link_max_length = layerm.region()->config().get_abs_value(surface.is_external() ? "external_fill_link_max_length" : "fill_link_max_length", flow.spacing());
664// printf("flow spacing: %f, is_external: %d, link_max_length: %lf\n", flow.spacing(), int(surface.is_external()), link_max_length);
665#else
666 if (surface_fill.params.density > 80.) // 80%
667 link_max_length = 3. * f->spacing;
668#endif
669 }
670
671 // Maximum length of the perimeter segment linking two infill lines.
672 f->link_max_length = (coord_t) scale_(link_max_length);
673 // Used by the concentric infill pattern to clip the loops to create extrusion paths.
674 f->loop_clipping = coord_t(scale_(surface_fill.params.flow.nozzle_diameter()) * LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER);
675
676 LayerRegion &layerm = *m_regions[surface_fill.region_id];
677
678 // apply half spacing using this flow's own spacing and generate infill
679 FillParams params;
680 params.density = float(0.01 * surface_fill.params.density);
681 params.dont_adjust = false; // surface_fill.params.dont_adjust;
682 params.anchor_length = surface_fill.params.anchor_length;
683 params.anchor_length_max = surface_fill.params.anchor_length_max;
684 params.resolution = resolution;
685 params.use_arachne = false;
686 params.layer_height = layerm.layer()->height;
687
688 for (ExPolygon &expoly : surface_fill.expolygons) {
689 // Spacing is modified by the filler to indicate adjustments. Reset it for each expolygon.
690 f->spacing = surface_fill.params.spacing;
691 surface_fill.surface.expolygon = std::move(expoly);
692 try {
693 Polylines polylines = f->fill_surface(&surface_fill.surface, params);
694 sparse_infill_polylines.insert(sparse_infill_polylines.end(), polylines.begin(), polylines.end());
695 } catch (InfillFailedException &) {}
696 }
697 }
698
699 return sparse_infill_polylines;
700}
Definition BoundingBox.hpp:181
static Fill * new_from_type(const InfillPattern type)
Definition FillBase.cpp:31
size_t id() const
Definition Layer.hpp:315
PrintObject * object()
Definition Layer.hpp:317
const PrintConfig & config() const
Definition Print.hpp:597
PrintType * print()
Definition PrintBase.hpp:735
BoundingBox bounding_box() const
Definition Print.hpp:261
const PrintObjectConfig & config() const
Definition Print.hpp:246
const Layer * get_layer(int idx) const
Definition Print.hpp:280
static constexpr double LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER
Definition libslic3r.h:60
#define scale_(val)
Definition libslic3r.h:69
@ ipStars
Definition PrintConfig.hpp:61
@ ipHilbertCurve
Definition PrintConfig.hpp:62
@ ipGrid
Definition PrintConfig.hpp:61
@ ipArchimedeanChords
Definition PrintConfig.hpp:62
@ ipConcentric
Definition PrintConfig.hpp:61
@ ipAlignedRectilinear
Definition PrintConfig.hpp:61
@ ipMonotonic
Definition PrintConfig.hpp:61
@ ipEnsuring
Definition PrintConfig.hpp:64
@ ip3DHoneycomb
Definition PrintConfig.hpp:61
@ ipAdaptiveCubic
Definition PrintConfig.hpp:62
@ ipMonotonicLines
Definition PrintConfig.hpp:61
@ ipCount
Definition PrintConfig.hpp:65
@ ipLine
Definition PrintConfig.hpp:61
@ ipHoneycomb
Definition PrintConfig.hpp:61
@ ipCubic
Definition PrintConfig.hpp:61
@ ipOctagramSpiral
Definition PrintConfig.hpp:62
@ ipTriangles
Definition PrintConfig.hpp:61
@ ipSupportCubic
Definition PrintConfig.hpp:62
@ ipRectilinear
Definition PrintConfig.hpp:61
@ ipGyroid
Definition PrintConfig.hpp:62
@ ipSupportBase
Definition PrintConfig.hpp:62
@ ipLightning
Definition PrintConfig.hpp:63
std::vector< Polyline > Polylines
Definition Polyline.hpp:14
std::vector< SurfaceFill > group_fills(const Layer &layer)
Definition Fill.cpp:121
static double f(double x, double z_sin, double z_cos, bool vertical, bool flip)
Definition FillGyroid.cpp:12
@ stInternal
Definition Surface.hpp:17

References Slic3r::FillParams::anchor_length, Slic3r::FillParams::anchor_length_max, Slic3r::FillParams::density, Slic3r::FillParams::dont_adjust, Slic3r::group_fills(), Slic3r::Layer::height, Slic3r::ip3DHoneycomb, Slic3r::ipAdaptiveCubic, Slic3r::ipAlignedRectilinear, Slic3r::ipArchimedeanChords, Slic3r::ipConcentric, Slic3r::ipCount, Slic3r::ipCubic, Slic3r::ipEnsuring, Slic3r::ipGrid, Slic3r::ipGyroid, Slic3r::ipHilbertCurve, Slic3r::ipHoneycomb, Slic3r::ipLightning, Slic3r::ipLine, Slic3r::ipMonotonic, Slic3r::ipMonotonicLines, Slic3r::ipOctagramSpiral, Slic3r::ipRectilinear, Slic3r::ipStars, Slic3r::ipSupportBase, Slic3r::ipSupportCubic, Slic3r::ipTriangles, Slic3r::LayerRegion::layer(), Slic3r::FillParams::layer_height, LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER, Slic3r::FillParams::resolution, scale_, Slic3r::stInternal, and Slic3r::FillParams::use_arachne.

+ Here is the call graph for this function:

◆ get_region() [1/2]

LayerRegion * Slic3r::Layer::get_region ( int  idx)
inlineinherited
345{ return m_regions[idx]; }

References Slic3r::Layer::m_regions.

◆ get_region() [2/2]

const LayerRegion * Slic3r::Layer::get_region ( int  idx) const
inlineinherited
344{ return m_regions[idx]; }

References Slic3r::Layer::m_regions.

Referenced by Slic3r::SupportSpotsGenerator::build_object_part_from_slice(), Slic3r::SupportSpotsGenerator::check_stability(), Slic3r::PrintObject::detect_surfaces_type(), Slic3r::insert_fills_into_islands(), and Slic3r::GCode::process_layer_single_object().

+ Here is the caller graph for this function:

◆ has_extrusions()

virtual bool Slic3r::SupportLayer::has_extrusions ( ) const
inlinevirtual

Reimplemented from Slic3r::Layer.

440{ return ! support_fills.empty(); }
bool empty() const
Definition ExtrusionEntityCollection.hpp:65
ExtrusionEntityCollection support_fills
Definition Layer.hpp:436

References Slic3r::ExtrusionEntityCollection::empty(), and support_fills.

Referenced by Slic3r::GCode::collect_layers_to_print().

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

◆ id()

◆ interface_id()

size_t Slic3r::SupportLayer::interface_id ( ) const
inline
443{ return m_interface_id; }

References m_interface_id.

Referenced by Slic3r::FFFSupport::generate_support_toolpaths().

+ Here is the caller graph for this function:

◆ make_fills() [1/2]

void Slic3r::Layer::make_fills ( )
inlineinherited
371{ this->make_fills(nullptr, nullptr, nullptr); }
void make_fills()
Definition Layer.hpp:371

References Slic3r::Layer::make_fills().

Referenced by Slic3r::Layer::make_fills().

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

◆ make_fills() [2/2]

void Slic3r::Layer::make_fills ( FillAdaptive::Octree adaptive_fill_octree,
FillAdaptive::Octree support_fill_octree,
FillLightning::Generator lightning_generator 
)
inherited
437{
438 this->clear_fills();
439
440#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
441// this->export_region_fill_surfaces_to_svg_debug("10_fill-initial");
442#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
443
444 std::vector<SurfaceFill> surface_fills = group_fills(*this);
445 const Slic3r::BoundingBox bbox = this->object()->bounding_box();
446 const auto resolution = this->object()->print()->config().gcode_resolution.value;
447 const auto perimeter_generator = this->object()->config().perimeter_generator;
448
449#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
450 {
451 static int iRun = 0;
452 export_group_fills_to_svg(debug_out_path("Layer-fill_surfaces-10_fill-final-%d.svg", iRun ++).c_str(), surface_fills);
453 }
454#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
455
456 size_t first_object_layer_id = this->object()->get_layer(0)->id();
457 for (SurfaceFill &surface_fill : surface_fills) {
458 // Create the filler object.
459 std::unique_ptr<Fill> f = std::unique_ptr<Fill>(Fill::new_from_type(surface_fill.params.pattern));
460 f->set_bounding_box(bbox);
461 // Layer ID is used for orienting the infill in alternating directions.
462 // Layer::id() returns layer ID including raft layers, subtract them to make the infill direction independent
463 // from raft.
464 f->layer_id = this->id() - first_object_layer_id;
465 f->z = this->print_z;
466 f->angle = surface_fill.params.angle;
467 f->adapt_fill_octree = (surface_fill.params.pattern == ipSupportCubic) ? support_fill_octree : adaptive_fill_octree;
468 f->print_config = &this->object()->print()->config();
469 f->print_object_config = &this->object()->config();
470
471 if (surface_fill.params.pattern == ipLightning)
472 dynamic_cast<FillLightning::Filler*>(f.get())->generator = lightning_generator;
473
474 if (surface_fill.params.pattern == ipEnsuring) {
475 auto *fill_ensuring = dynamic_cast<FillEnsuring *>(f.get());
476 assert(fill_ensuring != nullptr);
477 fill_ensuring->print_region_config = &m_regions[surface_fill.region_id]->region().config();
478 }
479
480 // calculate flow spacing for infill pattern generation
481 bool using_internal_flow = ! surface_fill.surface.is_solid() && ! surface_fill.params.bridge;
482 double link_max_length = 0.;
483 if (! surface_fill.params.bridge) {
484#if 0
485 link_max_length = layerm.region()->config().get_abs_value(surface.is_external() ? "external_fill_link_max_length" : "fill_link_max_length", flow.spacing());
486// printf("flow spacing: %f, is_external: %d, link_max_length: %lf\n", flow.spacing(), int(surface.is_external()), link_max_length);
487#else
488 if (surface_fill.params.density > 80.) // 80%
489 link_max_length = 3. * f->spacing;
490#endif
491 }
492
493 // Maximum length of the perimeter segment linking two infill lines.
494 f->link_max_length = (coord_t)scale_(link_max_length);
495 // Used by the concentric infill pattern to clip the loops to create extrusion paths.
496 f->loop_clipping = coord_t(scale_(surface_fill.params.flow.nozzle_diameter()) * LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER);
497
498 LayerRegion &layerm = *m_regions[surface_fill.region_id];
499
500 // apply half spacing using this flow's own spacing and generate infill
501 FillParams params;
502 params.density = float(0.01 * surface_fill.params.density);
503 params.dont_adjust = false; // surface_fill.params.dont_adjust;
504 params.anchor_length = surface_fill.params.anchor_length;
505 params.anchor_length_max = surface_fill.params.anchor_length_max;
506 params.resolution = resolution;
507 params.use_arachne = (perimeter_generator == PerimeterGeneratorType::Arachne && surface_fill.params.pattern == ipConcentric) || surface_fill.params.pattern == ipEnsuring;
508 params.layer_height = layerm.layer()->height;
509
510 for (ExPolygon &expoly : surface_fill.expolygons) {
511 // Spacing is modified by the filler to indicate adjustments. Reset it for each expolygon.
512 f->spacing = surface_fill.params.spacing;
513 surface_fill.surface.expolygon = std::move(expoly);
514 Polylines polylines;
515 ThickPolylines thick_polylines;
516 try {
517 if (params.use_arachne)
518 thick_polylines = f->fill_surface_arachne(&surface_fill.surface, params);
519 else
520 polylines = f->fill_surface(&surface_fill.surface, params);
521 } catch (InfillFailedException &) {
522 }
523 if (!polylines.empty() || !thick_polylines.empty()) {
524 // calculate actual flow from spacing (which might have been adjusted by the infill
525 // pattern generator)
526 double flow_mm3_per_mm = surface_fill.params.flow.mm3_per_mm();
527 double flow_width = surface_fill.params.flow.width();
528 if (using_internal_flow) {
529 // if we used the internal flow we're not doing a solid infill
530 // so we can safely ignore the slight variation that might have
531 // been applied to f->spacing
532 } else {
533 Flow new_flow = surface_fill.params.flow.with_spacing(float(f->spacing));
534 flow_mm3_per_mm = new_flow.mm3_per_mm();
535 flow_width = new_flow.width();
536 }
537 // Save into layer.
538 ExtrusionEntityCollection* eec = nullptr;
539 auto fill_begin = uint32_t(layerm.fills().size());
540 layerm.m_fills.entities.push_back(eec = new ExtrusionEntityCollection());
541 // Only concentric fills are not sorted.
542 eec->no_sort = f->no_sort();
543 if (params.use_arachne) {
544 for (const ThickPolyline &thick_polyline : thick_polylines) {
545 Flow new_flow = surface_fill.params.flow.with_spacing(float(f->spacing));
546
547 ExtrusionMultiPath multi_path = PerimeterGenerator::thick_polyline_to_multi_path(thick_polyline, surface_fill.params.extrusion_role, new_flow, scaled<float>(0.05), float(SCALED_EPSILON));
548 // Append paths to collection.
549 if (!multi_path.empty()) {
550 if (multi_path.paths.front().first_point() == multi_path.paths.back().last_point())
551 eec->entities.emplace_back(new ExtrusionLoop(std::move(multi_path.paths)));
552 else
553 eec->entities.emplace_back(new ExtrusionMultiPath(std::move(multi_path)));
554 }
555 }
556
557 thick_polylines.clear();
558 } else {
560 eec->entities, std::move(polylines),
561 surface_fill.params.extrusion_role,
562 flow_mm3_per_mm, float(flow_width), surface_fill.params.flow.height());
563 }
564 insert_fills_into_islands(*this, uint32_t(surface_fill.region_id), fill_begin, uint32_t(layerm.fills().size()));
565 }
566 }
567 }
568
569 for (LayerSlice &lslice : this->lslices_ex)
570 for (LayerIsland &island : lslice.islands) {
571 if (! island.thin_fills.empty()) {
572 // Copy thin fills into fills packed as a collection.
573 // Fills are always stored as collections, the rest of the pipeline (wipe into infill, G-code generator) relies on it.
574 LayerRegion &layerm = *this->get_region(island.perimeters.region());
575 ExtrusionEntityCollection &collection = *(new ExtrusionEntityCollection());
576 layerm.m_fills.entities.push_back(&collection);
577 collection.entities.reserve(island.thin_fills.size());
578 for (uint32_t fill_id : island.thin_fills)
579 collection.entities.push_back(layerm.thin_fills().entities[fill_id]->clone());
580 island.add_fill_range({ island.perimeters.region(), { uint32_t(layerm.m_fills.entities.size() - 1), uint32_t(layerm.m_fills.entities.size()) } });
581 }
582 // Sort the fills by region ID.
583 std::sort(island.fills.begin(), island.fills.end(), [](auto &l, auto &r){ return l.region() < r.region() || (l.region() == r.region() && *l.begin() < *r.begin()); });
584 // Compress continuous fill ranges of the same region.
585 {
586 size_t k = 0;
587 for (size_t i = 0; i < island.fills.size();) {
588 uint32_t region_id = island.fills[i].region();
589 uint32_t begin = *island.fills[i].begin();
590 uint32_t end = *island.fills[i].end();
591 size_t j = i + 1;
592 for (; j < island.fills.size() && island.fills[j].region() == region_id && *island.fills[j].begin() == end; ++ j)
593 end = *island.fills[j].end();
594 island.fills[k ++] = { region_id, { begin, end } };
595 i = j;
596 }
597 island.fills.erase(island.fills.begin() + k, island.fills.end());
598 }
599 }
600
601#ifndef NDEBUG
602 for (LayerRegion *layerm : m_regions)
603 for (const ExtrusionEntity *e : layerm->fills())
604 assert(dynamic_cast<const ExtrusionEntityCollection*>(e) != nullptr);
605#endif
606}
void clear_fills()
Definition Fill.cpp:427
const LayerRegion * get_region(int idx) const
Definition Layer.hpp:344
#define SCALED_EPSILON
Definition libslic3r.h:71
ExtrusionMultiPath thick_polyline_to_multi_path(const ThickPolyline &thick_polyline, ExtrusionRole role, const Flow &flow, float tolerance, float merge_tolerance)
Definition PerimeterGenerator.cpp:60
VoxelGridPtr clone(const VoxelGrid &grid)
Definition OpenVDBUtils.cpp:285
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
static void insert_fills_into_islands(Layer &layer, uint32_t fill_region_id, uint32_t fill_begin, uint32_t fill_end)
Definition Fill.cpp:341
std::vector< ThickPolyline > ThickPolylines
Definition Polyline.hpp:15
S::iterator begin(S &sh, const PathTag &)
Definition geometry_traits.hpp:614
S::iterator end(S &sh, const PathTag &)
Definition geometry_traits.hpp:620
unsigned __int32 uint32_t
Definition unistd.h:79

References Slic3r::FillParams::anchor_length, Slic3r::FillParams::anchor_length_max, Slic3r::debug_out_path(), Slic3r::FillParams::density, Slic3r::FillParams::dont_adjust, Slic3r::ExtrusionMultiPath::empty(), Slic3r::ExtrusionEntityCollection::entities, Slic3r::extrusion_entities_append_paths(), Slic3r::LayerRegion::fills(), Slic3r::group_fills(), Slic3r::Layer::height, Slic3r::insert_fills_into_islands(), Slic3r::ipConcentric, Slic3r::ipEnsuring, Slic3r::ipLightning, Slic3r::ipSupportCubic, Slic3r::LayerRegion::layer(), Slic3r::FillParams::layer_height, LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER, Slic3r::LayerRegion::m_fills, Slic3r::Flow::mm3_per_mm(), Slic3r::ExtrusionEntityCollection::no_sort, Slic3r::ExtrusionMultiPath::paths, Slic3r::FillParams::resolution, scale_, SCALED_EPSILON, Slic3r::ExtrusionEntityCollection::size(), Slic3r::LayerRegion::thin_fills(), Slic3r::FillParams::use_arachne, Slic3r::Flow::width(), and Slic3r::Flow::with_spacing().

+ Here is the call graph for this function:

◆ make_ironing()

void Slic3r::Layer::make_ironing ( )
inherited
704{
705 // LayerRegion::slices contains surfaces marked with SurfaceType.
706 // Here we want to collect top surfaces extruded with the same extruder.
707 // A surface will be ironed with the same extruder to not contaminate the print with another material leaking from the nozzle.
708
709 // First classify regions based on the extruder used.
710 struct IroningParams {
711 int extruder = -1;
712 bool just_infill = false;
713 // Spacing of the ironing lines, also to calculate the extrusion flow from.
714 double line_spacing;
715 // Height of the extrusion, to calculate the extrusion flow from.
716 double height;
717 double speed;
718 double angle;
719
720 bool operator<(const IroningParams &rhs) const {
721 if (this->extruder < rhs.extruder)
722 return true;
723 if (this->extruder > rhs.extruder)
724 return false;
725 if (int(this->just_infill) < int(rhs.just_infill))
726 return true;
727 if (int(this->just_infill) > int(rhs.just_infill))
728 return false;
729 if (this->line_spacing < rhs.line_spacing)
730 return true;
731 if (this->line_spacing > rhs.line_spacing)
732 return false;
733 if (this->height < rhs.height)
734 return true;
735 if (this->height > rhs.height)
736 return false;
737 if (this->speed < rhs.speed)
738 return true;
739 if (this->speed > rhs.speed)
740 return false;
741 if (this->angle < rhs.angle)
742 return true;
743 if (this->angle > rhs.angle)
744 return false;
745 return false;
746 }
747
748 bool operator==(const IroningParams &rhs) const {
749 return this->extruder == rhs.extruder && this->just_infill == rhs.just_infill &&
750 this->line_spacing == rhs.line_spacing && this->height == rhs.height && this->speed == rhs.speed &&
751 this->angle == rhs.angle;
752 }
753
754 LayerRegion *layerm;
755 uint32_t region_id;
756
757 // IdeaMaker: ironing
758 // ironing flowrate (5% percent)
759 // ironing speed (10 mm/sec)
760
761 // Kisslicer:
762 // iron off, Sweep, Group
763 // ironing speed: 15 mm/sec
764
765 // Cura:
766 // Pattern (zig-zag / concentric)
767 // line spacing (0.1mm)
768 // flow: from normal layer height. 10%
769 // speed: 20 mm/sec
770 };
771
772 std::vector<IroningParams> by_extruder;
773 double default_layer_height = this->object()->config().layer_height;
774
775 for (uint32_t region_id = 0; region_id < uint32_t(this->regions().size()); ++region_id)
776 if (LayerRegion *layerm = this->get_region(region_id); ! layerm->slices().empty()) {
777 IroningParams ironing_params;
778 const PrintRegionConfig &config = layerm->region().config();
779 if (config.ironing &&
780 (config.ironing_type == IroningType::AllSolid ||
781 (config.top_solid_layers > 0 &&
782 (config.ironing_type == IroningType::TopSurfaces ||
783 (config.ironing_type == IroningType::TopmostOnly && layerm->layer()->upper_layer == nullptr))))) {
784 if (config.perimeter_extruder == config.solid_infill_extruder || config.perimeters == 0) {
785 // Iron the whole face.
786 ironing_params.extruder = config.solid_infill_extruder;
787 } else {
788 // Iron just the infill.
789 ironing_params.extruder = config.solid_infill_extruder;
790 }
791 }
792 if (ironing_params.extruder != -1) {
793 //TODO just_infill is currently not used.
794 ironing_params.just_infill = false;
795 ironing_params.line_spacing = config.ironing_spacing;
796 ironing_params.height = default_layer_height * 0.01 * config.ironing_flowrate;
797 ironing_params.speed = config.ironing_speed;
798 ironing_params.angle = config.fill_angle * M_PI / 180.;
799 ironing_params.layerm = layerm;
800 ironing_params.region_id = region_id;
801 by_extruder.emplace_back(ironing_params);
802 }
803 }
804 std::sort(by_extruder.begin(), by_extruder.end());
805
806 FillRectilinear fill;
807 FillParams fill_params;
808 fill.set_bounding_box(this->object()->bounding_box());
809 // Layer ID is used for orienting the infill in alternating directions.
810 // Layer::id() returns layer ID including raft layers, subtract them to make the infill direction independent
811 // from raft.
812 //FIXME ironing does not take fill angle into account. Shall it? Does it matter?
813 fill.layer_id = this->id() - this->object()->get_layer(0)->id();
814 fill.z = this->print_z;
815 fill.overlap = 0;
816 fill_params.density = 1.;
817 fill_params.monotonic = true;
818
819 for (size_t i = 0; i < by_extruder.size();) {
820 // Find span of regions equivalent to the ironing operation.
821 IroningParams &ironing_params = by_extruder[i];
822 size_t j = i;
823 for (++ j; j < by_extruder.size() && ironing_params == by_extruder[j]; ++ j) ;
824
825 // Create the ironing extrusions for regions <i, j)
826 ExPolygons ironing_areas;
827 double nozzle_dmr = this->object()->print()->config().nozzle_diameter.values[ironing_params.extruder - 1];
828 if (ironing_params.just_infill) {
829 //TODO just_infill is currently not used.
830 // Just infill.
831 } else {
832 // Infill and perimeter.
833 // Merge top surfaces with the same ironing parameters.
834 Polygons polys;
835 Polygons infills;
836 for (size_t k = i; k < j; ++ k) {
837 const IroningParams &ironing_params = by_extruder[k];
838 const PrintRegionConfig &region_config = ironing_params.layerm->region().config();
839 bool iron_everything = region_config.ironing_type == IroningType::AllSolid;
840 bool iron_completely = iron_everything;
841 if (iron_everything) {
842 // Check whether there is any non-solid hole in the regions.
843 bool internal_infill_solid = region_config.fill_density.value > 95.;
844 for (const Surface &surface : ironing_params.layerm->fill_surfaces())
845 if ((! internal_infill_solid && surface.surface_type == stInternal) || surface.surface_type == stInternalBridge || surface.surface_type == stInternalVoid) {
846 // Some fill region is not quite solid. Don't iron over the whole surface.
847 iron_completely = false;
848 break;
849 }
850 }
851 if (iron_completely) {
852 // Iron everything. This is likely only good for solid transparent objects.
853 for (const Surface &surface : ironing_params.layerm->slices())
854 polygons_append(polys, surface.expolygon);
855 } else {
856 for (const Surface &surface : ironing_params.layerm->slices())
857 if (surface.surface_type == stTop || (iron_everything && surface.surface_type == stBottom))
858 // stBottomBridge is not being ironed on purpose, as it would likely destroy the bridges.
859 polygons_append(polys, surface.expolygon);
860 }
861 if (iron_everything && ! iron_completely) {
862 // Add solid fill surfaces. This may not be ideal, as one will not iron perimeters touching these
863 // solid fill surfaces, but it is likely better than nothing.
864 for (const Surface &surface : ironing_params.layerm->fill_surfaces())
865 if (surface.surface_type == stInternalSolid)
866 polygons_append(infills, surface.expolygon);
867 }
868 }
869
870 if (! infills.empty() || j > i + 1) {
871 // Ironing over more than a single region or over solid internal infill.
872 if (! infills.empty())
873 // For IroningType::AllSolid only:
874 // Add solid infill areas for layers, that contain some non-ironable infil (sparse infill, bridge infill).
875 append(polys, std::move(infills));
876 polys = union_safety_offset(polys);
877 }
878 // Trim the top surfaces with half the nozzle diameter.
879 ironing_areas = intersection_ex(polys, offset(this->lslices, - float(scale_(0.5 * nozzle_dmr))));
880 }
881
882 // Create the filler object.
883 fill.spacing = ironing_params.line_spacing;
884 fill.angle = float(ironing_params.angle + 0.25 * M_PI);
885 fill.link_max_length = (coord_t)scale_(3. * fill.spacing);
886 double extrusion_height = ironing_params.height * fill.spacing / nozzle_dmr;
887 float extrusion_width = Flow::rounded_rectangle_extrusion_width_from_spacing(float(nozzle_dmr), float(extrusion_height));
888 double flow_mm3_per_mm = nozzle_dmr * extrusion_height;
889 Surface surface_fill(stTop, ExPolygon());
890 for (ExPolygon &expoly : ironing_areas) {
891 surface_fill.expolygon = std::move(expoly);
892 Polylines polylines;
893 try {
894 assert(!fill_params.use_arachne);
895 polylines = fill.fill_surface(&surface_fill, fill_params);
896 } catch (InfillFailedException &) {
897 }
898 if (! polylines.empty()) {
899 // Save into layer.
900 auto fill_begin = uint32_t(ironing_params.layerm->fills().size());
901 ExtrusionEntityCollection *eec = nullptr;
902 ironing_params.layerm->m_fills.entities.push_back(eec = new ExtrusionEntityCollection());
903 // Don't sort the ironing infill lines as they are monotonicly ordered.
904 eec->no_sort = true;
906 eec->entities, std::move(polylines),
908 flow_mm3_per_mm, extrusion_width, float(extrusion_height));
909 insert_fills_into_islands(*this, ironing_params.region_id, fill_begin, uint32_t(ironing_params.layerm->fills().size()));
910 }
911 }
912
913 // Regions up to j were processed.
914 i = j;
915 }
916}
#define M_PI
Definition ExtrusionSimulator.cpp:20
static float rounded_rectangle_extrusion_width_from_spacing(float spacing, float height)
Definition Flow.cpp:194
ExPolygons lslices
Definition Layer.hpp:339
const LayerRegionPtrs & regions() const
Definition Layer.hpp:347
const SurfaceCollection & slices() const
Definition Layer.hpp:103
bool empty() const
Definition SurfaceCollection.hpp:44
bool operator==(const IntPoint &l, const IntPoint &r)
Definition clipper.cpp:93
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bool operator<(const half &a, const half &b)
Definition Half.h:307
coord_t height(const BoundingBox &box)
Definition Arrange.cpp:540
std::vector< Polygon, PointsAllocator< Polygon > > Polygons
Definition Polygon.hpp:15
BoundingBoxf3 bounding_box(const TriangleMesh &m)
Definition TriangleMesh.hpp:340
PrintRegionConfig
Definition PrintConfig.hpp:840
std::vector< ExPolygon > ExPolygons
Definition ExPolygon.hpp:13
Slic3r::Polygons offset(const Slic3r::Polygon &polygon, const float delta, ClipperLib::JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:416
double angle(const Eigen::MatrixBase< Derived > &v1, const Eigen::MatrixBase< Derived2 > &v2)
Definition Point.hpp:112
Slic3r::ExPolygons intersection_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset)
Definition ClipperUtils.cpp:755
Slic3r::Polygons union_safety_offset(const Slic3r::Polygons &polygons)
Definition ClipperUtils.hpp:352
void polygons_append(Polygons &dst, const ExPolygon &src)
Definition ExPolygon.hpp:375
@ stInternalSolid
Definition Surface.hpp:19
@ stTop
Definition Surface.hpp:11
@ stInternalBridge
Definition Surface.hpp:21
@ stBottom
Definition Surface.hpp:13
@ stInternalVoid
Definition Surface.hpp:24
void append(std::vector< T, Alloc > &dest, const std::vector< T, Alloc2 > &src)
Definition libslic3r.h:110
constexpr auto size(const C &c) -> decltype(c.size())
Definition span.hpp:183
static constexpr const ExtrusionRoleModifiers Ironing
Definition ExtrusionRole.hpp:62

References Slic3r::Fill::angle, Slic3r::angle(), Slic3r::FillParams::density, Slic3r::SurfaceCollection::empty(), Slic3r::ExtrusionEntityCollection::entities, Slic3r::Surface::expolygon, Slic3r::extrusion_entities_append_paths(), Slic3r::FillRectilinear::fill_surface(), Slic3r::insert_fills_into_islands(), Slic3r::intersection_ex(), Slic3r::Fill::layer_id, Slic3r::Fill::link_max_length, M_PI, Slic3r::FillParams::monotonic, Slic3r::ExtrusionEntityCollection::no_sort, Slic3r::Fill::overlap, Slic3r::polygons_append(), Slic3r::PrintRegionConfig, scale_, Slic3r::Fill::set_bounding_box(), Slic3r::LayerRegion::slices(), Slic3r::Fill::spacing, Slic3r::stBottom, Slic3r::stInternal, Slic3r::stInternalBridge, Slic3r::stInternalSolid, Slic3r::stInternalVoid, Slic3r::stTop, Slic3r::union_safety_offset(), Slic3r::FillParams::use_arachne, and Slic3r::Fill::z.

+ Here is the call graph for this function:

◆ make_perimeters()

void Slic3r::Layer::make_perimeters ( )
inherited
615{
616 BOOST_LOG_TRIVIAL(trace) << "Generating perimeters for layer " << this->id();
617
618 // keep track of regions whose perimeters we have already generated
619 std::vector<unsigned char> done(m_regions.size(), false);
620 std::vector<uint32_t> layer_region_ids;
621 std::vector<std::pair<ExtrusionRange, ExtrusionRange>> perimeter_and_gapfill_ranges;
622 ExPolygons fill_expolygons;
623 std::vector<ExPolygonRange> fill_expolygons_ranges;
624 SurfacesPtr surfaces_to_merge;
625 SurfacesPtr surfaces_to_merge_temp;
626
627 auto layer_region_reset_perimeters = [](LayerRegion &layerm) {
628 layerm.m_perimeters.clear();
629 layerm.m_fills.clear();
630 layerm.m_thin_fills.clear();
631 layerm.m_fill_expolygons.clear();
632 layerm.m_fill_expolygons_bboxes.clear();
633 layerm.m_fill_expolygons_composite.clear();
634 layerm.m_fill_expolygons_composite_bboxes.clear();
635 };
636
637 // Remove layer islands, remove references to perimeters and fills from these layer islands to LayerRegion ExtrusionEntities.
638 for (LayerSlice &lslice : this->lslices_ex)
639 lslice.islands.clear();
640
641 for (LayerRegionPtrs::iterator layerm = m_regions.begin(); layerm != m_regions.end(); ++ layerm)
642 if (size_t region_id = layerm - m_regions.begin(); ! done[region_id]) {
643 layer_region_reset_perimeters(**layerm);
644 if (! (*layerm)->slices().empty()) {
645 BOOST_LOG_TRIVIAL(trace) << "Generating perimeters for layer " << this->id() << ", region " << region_id;
646 done[region_id] = true;
647 const PrintRegionConfig &config = (*layerm)->region().config();
648
649 perimeter_and_gapfill_ranges.clear();
650 fill_expolygons.clear();
651 fill_expolygons_ranges.clear();
652 surfaces_to_merge.clear();
653
654 // find compatible regions
655 layer_region_ids.clear();
656 layer_region_ids.push_back(region_id);
657 for (LayerRegionPtrs::const_iterator it = layerm + 1; it != m_regions.end(); ++it)
658 if (! (*it)->slices().empty()) {
659 LayerRegion *other_layerm = *it;
660 const PrintRegionConfig &other_config = other_layerm->region().config();
661 bool dynamic_overhang_speed_compatibility = config.enable_dynamic_overhang_speeds ==
662 other_config.enable_dynamic_overhang_speeds;
663 if (dynamic_overhang_speed_compatibility && config.enable_dynamic_overhang_speeds) {
664 dynamic_overhang_speed_compatibility = config.overhang_speed_0 == other_config.overhang_speed_0 &&
665 config.overhang_speed_1 == other_config.overhang_speed_1 &&
666 config.overhang_speed_2 == other_config.overhang_speed_2 &&
667 config.overhang_speed_3 == other_config.overhang_speed_3;
668 }
669
670 if (config.perimeter_extruder == other_config.perimeter_extruder
671 && config.perimeters == other_config.perimeters
672 && config.perimeter_speed == other_config.perimeter_speed
673 && config.external_perimeter_speed == other_config.external_perimeter_speed
674 && dynamic_overhang_speed_compatibility
675 && (config.gap_fill_enabled ? config.gap_fill_speed.value : 0.) ==
676 (other_config.gap_fill_enabled ? other_config.gap_fill_speed.value : 0.)
677 && config.overhangs == other_config.overhangs
678 && config.opt_serialize("perimeter_extrusion_width") == other_config.opt_serialize("perimeter_extrusion_width")
679 && config.thin_walls == other_config.thin_walls
681 && config.infill_overlap == other_config.infill_overlap
682 && config.fuzzy_skin == other_config.fuzzy_skin
683 && config.fuzzy_skin_thickness == other_config.fuzzy_skin_thickness
684 && config.fuzzy_skin_point_dist == other_config.fuzzy_skin_point_dist)
685 {
686 layer_region_reset_perimeters(*other_layerm);
687 layer_region_ids.push_back(it - m_regions.begin());
688 done[it - m_regions.begin()] = true;
689 }
690 }
691
692 if (layer_region_ids.size() == 1) { // optimization
693 (*layerm)->make_perimeters((*layerm)->slices(), perimeter_and_gapfill_ranges, fill_expolygons, fill_expolygons_ranges);
694 this->sort_perimeters_into_islands((*layerm)->slices(), region_id, perimeter_and_gapfill_ranges, std::move(fill_expolygons), fill_expolygons_ranges, layer_region_ids);
695 } else {
696 SurfaceCollection new_slices;
697 // Use the region with highest infill rate, as the make_perimeters() function below decides on the gap fill based on the infill existence.
698 uint32_t region_id_config = layer_region_ids.front();
699 LayerRegion* layerm_config = m_regions[region_id_config];
700 {
701 // Merge slices (surfaces) according to number of extra perimeters.
702 for (uint32_t region_id : layer_region_ids) {
703 LayerRegion &layerm = *m_regions[region_id];
704 for (const Surface &surface : layerm.slices())
705 surfaces_to_merge.emplace_back(&surface);
706 if (layerm.region().config().fill_density > layerm_config->region().config().fill_density) {
707 region_id_config = region_id;
708 layerm_config = &layerm;
709 }
710 }
711 std::sort(surfaces_to_merge.begin(), surfaces_to_merge.end(), [](const Surface *l, const Surface *r){ return l->extra_perimeters < r->extra_perimeters; });
712 for (size_t i = 0; i < surfaces_to_merge.size();) {
713 size_t j = i;
714 const Surface &first = *surfaces_to_merge[i];
715 size_t extra_perimeters = first.extra_perimeters;
716 for (; j < surfaces_to_merge.size() && surfaces_to_merge[j]->extra_perimeters == extra_perimeters; ++ j) ;
717 if (i + 1 == j)
718 // Nothing to merge, just copy.
719 new_slices.surfaces.emplace_back(*surfaces_to_merge[i]);
720 else {
721 surfaces_to_merge_temp.assign(surfaces_to_merge.begin() + i, surfaces_to_merge.begin() + j);
722 new_slices.append(offset_ex(surfaces_to_merge_temp, ClipperSafetyOffset), first);
723 }
724 i = j;
725 }
726 }
727 // make perimeters
728 layerm_config->make_perimeters(new_slices, perimeter_and_gapfill_ranges, fill_expolygons, fill_expolygons_ranges);
729 this->sort_perimeters_into_islands(new_slices, region_id_config, perimeter_and_gapfill_ranges, std::move(fill_expolygons), fill_expolygons_ranges, layer_region_ids);
730 }
731 }
732 }
733 BOOST_LOG_TRIVIAL(trace) << "Generating perimeters for layer " << this->id() << " - Done";
734}
static volatile int done
Definition bitbang.c:50
void sort_perimeters_into_islands(const SurfaceCollection &slices, const uint32_t region_id, const std::vector< std::pair< ExtrusionRange, ExtrusionRange > > &perimeter_and_gapfill_ranges, ExPolygons &&fill_expolygons, const std::vector< ExPolygonRange > &fill_expolygons_ranges, const std::vector< uint32_t > &layer_region_ids)
Definition Layer.cpp:736
std::vector< const Surface * > SurfacesPtr
Definition Surface.hpp:98
fuzzy_skin_point_dist((ConfigOptionBool, gap_fill_enabled))((ConfigOptionFloat
Slic3r::ExPolygons offset_ex(const Slic3r::Polygons &polygons, const float delta, ClipperLib::JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:421
gap_fill_speed((ConfigOptionFloatOrPercent, infill_anchor))((ConfigOptionFloatOrPercent
fuzzy_skin((ConfigOptionFloat, fuzzy_skin_thickness))((ConfigOptionFloat
infill_overlap((ConfigOptionFloat, infill_speed))((ConfigOptionBool
external_perimeters_first((ConfigOptionBool, extra_perimeters))((ConfigOptionBool
thin_walls((ConfigOptionFloatOrPercent, top_infill_extrusion_width))((ConfigOptionInt
static constexpr const float ClipperSafetyOffset
Definition ClipperUtils.hpp:29

References Slic3r::SurfaceCollection::append(), Slic3r::PrintRegion::config(), done, Slic3r::Surface::extra_perimeters, Slic3r::LayerRegion::make_perimeters(), Slic3r::offset_ex(), Slic3r::PrintRegionConfig, Slic3r::LayerRegion::region(), Slic3r::LayerRegion::slices(), and Slic3r::SurfaceCollection::surfaces.

+ Here is the call graph for this function:

◆ make_slices()

void Slic3r::Layer::make_slices ( )
inherited
43{
44 {
45 ExPolygons slices;
46 if (m_regions.size() == 1) {
47 // optimization: if we only have one region, take its slices
48 slices = to_expolygons(m_regions.front()->slices().surfaces);
49 } else {
50 Polygons slices_p;
51 for (LayerRegion *layerm : m_regions)
52 polygons_append(slices_p, to_polygons(layerm->slices().surfaces));
53 slices = union_safety_offset_ex(slices_p);
54 }
55 // lslices are sorted by topological order from outside to inside from the clipper union used above
56 this->lslices = slices;
57 }
58
60}
std::vector< size_t > lslice_indices_sorted_by_print_order
Definition Layer.hpp:340
Polygons to_polygons(const ExPolygon &src)
Definition ExPolygon.hpp:281
Slic3r::ExPolygons union_safety_offset_ex(const Slic3r::Polygons &polygons)
Definition ClipperUtils.hpp:354
std::vector< size_t > chain_expolygons(const ExPolygons &expolygons, Point *start_near)
Definition ShortestPath.cpp:1079

References Slic3r::chain_expolygons(), Slic3r::Layer::lslice_indices_sorted_by_print_order, Slic3r::Layer::lslices, Slic3r::Layer::m_regions, Slic3r::polygons_append(), Slic3r::to_expolygons(), Slic3r::to_polygons(), and Slic3r::union_safety_offset_ex().

+ Here is the call graph for this function:

◆ merged()

ExPolygons Slic3r::Layer::merged ( float  offset) const
inherited
590{
591 assert(offset_scaled >= 0.f);
592 // If no offset is set, apply EPSILON offset before union, and revert it afterwards.
593 float offset_scaled2 = 0;
594 if (offset_scaled == 0.f) {
595 offset_scaled = float( EPSILON);
596 offset_scaled2 = float(- EPSILON);
597 }
598 Polygons polygons;
599 for (LayerRegion *layerm : m_regions) {
600 const PrintRegionConfig &config = layerm->region().config();
601 // Our users learned to bend Slic3r to produce empty volumes to act as subtracters. Only add the region if it is non-empty.
602 if (config.bottom_solid_layers > 0 || config.top_solid_layers > 0 || config.fill_density > 0. || config.perimeters > 0)
603 append(polygons, offset(layerm->slices().surfaces, offset_scaled));
604 }
605 ExPolygons out = union_ex(polygons);
606 if (offset_scaled2 != 0.f)
607 out = offset_ex(out, offset_scaled2);
608 return out;
609}
static constexpr double EPSILON
Definition libslic3r.h:51
Slic3r::ExPolygons union_ex(const Slic3r::Polygons &subject, ClipperLib::PolyFillType fill_type)
Definition ClipperUtils.cpp:774

References EPSILON, Slic3r::offset_ex(), Slic3r::PrintRegionConfig, and Slic3r::union_ex().

+ Here is the call graph for this function:

◆ object() [1/2]

◆ object() [2/2]

const PrintObject * Slic3r::Layer::object ( ) const
inlineinherited
318{ return m_object; }

References Slic3r::Layer::m_object.

◆ region_count()

size_t Slic3r::Layer::region_count ( ) const
inlineinherited
343{ return m_regions.size(); }

References Slic3r::Layer::m_regions.

Referenced by Slic3r::FFFTreeSupport::generate_overhangs().

+ Here is the caller graph for this function:

◆ regions()

◆ restore_untyped_slices()

void Slic3r::Layer::restore_untyped_slices ( )
inherited
560{
561 if (layer_needs_raw_backup(this)) {
562 for (LayerRegion *layerm : m_regions)
563 layerm->m_slices.set(layerm->m_raw_slices, stInternal);
564 } else {
565 assert(m_regions.size() == 1);
566 m_regions.front()->m_slices.set(this->lslices, stInternal);
567 }
568}

References Slic3r::layer_needs_raw_backup(), and Slic3r::stInternal.

+ Here is the call graph for this function:

◆ restore_untyped_slices_no_extra_perimeters()

void Slic3r::Layer::restore_untyped_slices_no_extra_perimeters ( )
inherited
575{
576 if (layer_needs_raw_backup(this)) {
577 for (LayerRegion *layerm : m_regions)
578 if (! layerm->region().config().extra_perimeters.value)
579 layerm->m_slices.set(layerm->m_raw_slices, stInternal);
580 } else {
581 assert(m_regions.size() == 1);
582 LayerRegion *layerm = m_regions.front();
583 // This optimization is correct, as extra_perimeters are only reused by prepare_infill() with multi-regions.
584 //if (! layerm->region().config().extra_perimeters.value)
585 layerm->m_slices.set(this->lslices, stInternal);
586 }
587}

References Slic3r::layer_needs_raw_backup(), Slic3r::LayerRegion::m_slices, Slic3r::SurfaceCollection::set(), and Slic3r::stInternal.

+ Here is the call graph for this function:

◆ set_id()

void Slic3r::Layer::set_id ( size_t  id)
inlineinherited
316{ m_id = id; }

References Slic3r::Layer::id(), and Slic3r::Layer::m_id.

+ Here is the call graph for this function:

◆ sort_perimeters_into_islands()

void Slic3r::Layer::sort_perimeters_into_islands ( const SurfaceCollection slices,
const uint32_t  region_id,
const std::vector< std::pair< ExtrusionRange, ExtrusionRange > > &  perimeter_and_gapfill_ranges,
ExPolygons &&  fill_expolygons,
const std::vector< ExPolygonRange > &  fill_expolygons_ranges,
const std::vector< uint32_t > &  layer_region_ids 
)
privateinherited
751{
752 assert(perimeter_and_gapfill_ranges.size() == fill_expolygons_ranges.size());
753 assert(! layer_region_ids.empty());
754
755 LayerRegion &this_layer_region = *m_regions[region_id];
756
757 // Bounding boxes of fill_expolygons.
758 BoundingBoxes fill_expolygons_bboxes;
759 fill_expolygons_bboxes.reserve(fill_expolygons.size());
760 for (const ExPolygon &expolygon : fill_expolygons)
761 fill_expolygons_bboxes.emplace_back(get_extents(expolygon));
762
763 // Take one sample point for each source slice, to be used to sort source slices into layer slices.
764 // source slice index + its sample.
765 std::vector<std::pair<uint32_t, Point>> perimeter_slices_queue;
766 perimeter_slices_queue.reserve(slices.size());
767 for (uint32_t islice = 0; islice < uint32_t(slices.size()); ++ islice) {
768 const std::pair<ExtrusionRange, ExtrusionRange> &extrusions = perimeter_and_gapfill_ranges[islice];
769 Point sample;
770 bool sample_set = false;
771 // Take a sample deep inside its island if available. Infills are usually quite far from the island boundary.
772 for (uint32_t iexpoly : fill_expolygons_ranges[islice])
773 if (const ExPolygon &expoly = fill_expolygons[iexpoly]; ! expoly.empty()) {
774 sample = expoly.contour.points[expoly.contour.points.size() / 2];
775 sample_set = true;
776 break;
777 }
778 if (! sample_set) {
779 // If there is no infill, take a sample of some inner perimeter.
780 for (uint32_t iperimeter : extrusions.first) {
781 const ExtrusionEntity &ee = *this_layer_region.perimeters().entities[iperimeter];
782 if (ee.is_collection()) {
783 for (const ExtrusionEntity *ee2 : dynamic_cast<const ExtrusionEntityCollection&>(ee).entities)
784 if (! ee2->role().is_external()) {
785 sample = ee2->middle_point();
786 sample_set = true;
787 goto loop_end;
788 }
789 } else if (! ee.role().is_external()) {
790 sample = ee.middle_point();
791 sample_set = true;
792 break;
793 }
794 }
795 loop_end:
796 if (! sample_set) {
797 if (! extrusions.second.empty()) {
798 // If there is no inner perimeter, take a sample of some gap fill extrusion.
799 sample = this_layer_region.thin_fills().entities[*extrusions.second.begin()]->middle_point();
800 sample_set = true;
801 }
802 if (! sample_set && ! extrusions.first.empty()) {
803 // As a last resort, take a sample of some external perimeter.
804 sample = this_layer_region.perimeters().entities[*extrusions.first.begin()]->middle_point();
805 sample_set = true;
806 }
807 }
808 }
809 // There may be a valid empty island.
810 // assert(sample_set);
811 if (sample_set)
812 perimeter_slices_queue.emplace_back(islice, sample);
813 }
814
815 // Map of source fill_expolygon into region and fill_expolygon of that region.
816 // -1: not set
817 struct RegionWithFillIndex {
818 int region_id{ -1 };
819 int fill_in_region_id{ -1 };
820 };
821 std::vector<RegionWithFillIndex> map_expolygon_to_region_and_fill;
822 const bool has_multiple_regions = layer_region_ids.size() > 1;
823 assert(has_multiple_regions || layer_region_ids.size() == 1);
824 // assign fill_surfaces to each layer
825 if (! fill_expolygons.empty()) {
826 if (has_multiple_regions) {
827 // Sort the bounding boxes lexicographically.
828 std::vector<uint32_t> fill_expolygons_bboxes_sorted(fill_expolygons_bboxes.size());
829 std::iota(fill_expolygons_bboxes_sorted.begin(), fill_expolygons_bboxes_sorted.end(), 0);
830 std::sort(fill_expolygons_bboxes_sorted.begin(), fill_expolygons_bboxes_sorted.end(), [&fill_expolygons_bboxes](uint32_t lhs, uint32_t rhs){
831 const BoundingBox &bbl = fill_expolygons_bboxes[lhs];
832 const BoundingBox &bbr = fill_expolygons_bboxes[rhs];
833 return bbl.min < bbr.min || (bbl.min == bbr.min && bbl.max < bbr.max);
834 });
835 map_expolygon_to_region_and_fill.assign(fill_expolygons.size(), {});
836 for (uint32_t region_idx : layer_region_ids) {
837 LayerRegion &l = *m_regions[region_idx];
838 l.m_fill_expolygons = intersection_ex(l.slices().surfaces, fill_expolygons);
839 l.m_fill_expolygons_bboxes.reserve(l.fill_expolygons().size());
840 for (const ExPolygon &expolygon : l.fill_expolygons()) {
841 BoundingBox bbox = get_extents(expolygon);
842 l.m_fill_expolygons_bboxes.emplace_back(bbox);
843 auto it_bbox = std::lower_bound(fill_expolygons_bboxes_sorted.begin(), fill_expolygons_bboxes_sorted.end(), bbox, [&fill_expolygons_bboxes](uint32_t lhs, const BoundingBox &bbr){
844 const BoundingBox &bbl = fill_expolygons_bboxes[lhs];
845 return bbl.min < bbr.min || (bbl.min == bbr.min && bbl.max < bbr.max);
846 });
847 if (it_bbox != fill_expolygons_bboxes_sorted.end())
848 if (uint32_t fill_id = *it_bbox; fill_expolygons_bboxes[fill_id] == bbox) {
849 // With a very high probability the two expolygons match exactly. Confirm that.
850 if (expolygons_match(expolygon, fill_expolygons[fill_id])) {
851 RegionWithFillIndex &ref = map_expolygon_to_region_and_fill[fill_id];
852 // Only one expolygon produced by intersection with LayerRegion surface may match an expolygon of fill_expolygons.
853 assert(ref.region_id == -1 && ref.fill_in_region_id == -1);
854 ref.region_id = region_idx;
855 ref.fill_in_region_id = int(&expolygon - l.fill_expolygons().data());
856 }
857 }
858 }
859 }
860 // Check whether any island contains multiple fills that fall into the same region, but not they are not contiguous.
861 // If so, sort fills in that particular region so that fills of an island become contiguous.
862 // Index of a region to sort.
863 int sort_region_id = -1;
864 // Temporary vector of fills for reordering.
865 ExPolygons fills_temp;
866 // Vector of new positions of the above.
867 std::vector<int> new_positions;
868 do {
869 sort_region_id = -1;
870 for (size_t source_slice_idx = 0; source_slice_idx < fill_expolygons_ranges.size(); ++ source_slice_idx)
871 if (ExPolygonRange fill_range = fill_expolygons_ranges[source_slice_idx]; fill_range.size() > 1) {
872 // More than one expolygon exists for a single island. Check whether they are contiguous inside a single LayerRegion::fill_expolygons() vector.
873 uint32_t fill_idx = *fill_range.begin();
874 if (const int fill_regon_id = map_expolygon_to_region_and_fill[fill_idx].region_id; fill_regon_id != -1) {
875 int fill_in_region_id = map_expolygon_to_region_and_fill[fill_idx].fill_in_region_id;
876 bool needs_sorting = false;
877 for (++ fill_idx; fill_idx != *fill_range.end(); ++ fill_idx) {
878 if (const RegionWithFillIndex &ref = map_expolygon_to_region_and_fill[fill_idx]; ref.region_id != fill_regon_id) {
879 // This island has expolygons split among multiple regions.
880 needs_sorting = false;
881 break;
882 } else if (ref.fill_in_region_id != ++ fill_in_region_id) {
883 // This island has all expolygons stored inside the same region, but not sorted.
884 needs_sorting = true;
885 }
886 }
887 if (needs_sorting) {
888 sort_region_id = fill_regon_id;
889 break;
890 }
891 }
892 }
893 if (sort_region_id != -1) {
894 // Reorder fills in region with sort_region index.
895 LayerRegion &layerm = *m_regions[sort_region_id];
896 new_positions.assign(layerm.fill_expolygons().size(), -1);
897 int last = 0;
898 for (RegionWithFillIndex &ref : map_expolygon_to_region_and_fill)
899 if (ref.region_id == sort_region_id) {
900 new_positions[ref.fill_in_region_id] = last;
901 ref.fill_in_region_id = last ++;
902 }
903 for (auto &new_pos : new_positions)
904 if (new_pos == -1)
905 // Not referenced by any map_expolygon_to_region_and_fill.
906 new_pos = last ++;
907 // Move just the content of m_fill_expolygons to fills_temp, but don't move the container vector.
908 auto &fills = layerm.m_fill_expolygons;
909 assert(last == int(fills.size()));
910 fills_temp.reserve(fills.size());
911 fills_temp.insert(fills_temp.end(), std::make_move_iterator(fills.begin()), std::make_move_iterator(fills.end()));
912 for (ExPolygon &ex : fills)
913 ex.clear();
914 // Move / reoder the expolygons back into m_fill_expolygons.
915 for (size_t old_pos = 0; old_pos < new_positions.size(); ++ old_pos)
916 fills[new_positions[old_pos]] = std::move(fills_temp[old_pos]);
917 }
918 } while (sort_region_id != -1);
919 } else {
920 this_layer_region.m_fill_expolygons = std::move(fill_expolygons);
921 this_layer_region.m_fill_expolygons_bboxes = std::move(fill_expolygons_bboxes);
922 }
923 }
924
925 auto insert_into_island = [
926 // Region where the perimeters, gap fills and fill expolygons are stored.
927 region_id,
928 // Whether there are infills with different regions generated for this LayerSlice.
929 has_multiple_regions,
930 // Perimeters and gap fills to be sorted into islands.
931 &perimeter_and_gapfill_ranges,
932 // Infill regions to be sorted into islands.
933 &fill_expolygons, &fill_expolygons_bboxes, &fill_expolygons_ranges,
934 // Mapping of fill_expolygon to region and its infill.
935 &map_expolygon_to_region_and_fill,
936 // Output
938 (int lslice_idx, int source_slice_idx) {
939 lslices_ex[lslice_idx].islands.push_back({});
940 LayerIsland &island = lslices_ex[lslice_idx].islands.back();
941 island.perimeters = LayerExtrusionRange(region_id, perimeter_and_gapfill_ranges[source_slice_idx].first);
942 island.thin_fills = perimeter_and_gapfill_ranges[source_slice_idx].second;
943 if (ExPolygonRange fill_range = fill_expolygons_ranges[source_slice_idx]; ! fill_range.empty()) {
944 if (has_multiple_regions) {
945 // Check whether the fill expolygons of this island were split into multiple regions.
946 island.fill_region_id = LayerIsland::fill_region_composite_id;
947 for (uint32_t fill_idx : fill_range) {
948 if (const int fill_regon_id = map_expolygon_to_region_and_fill[fill_idx].region_id;
949 fill_regon_id == -1 || (island.fill_region_id != LayerIsland::fill_region_composite_id && int(island.fill_region_id) != fill_regon_id)) {
950 island.fill_region_id = LayerIsland::fill_region_composite_id;
951 break;
952 } else
953 island.fill_region_id = fill_regon_id;
954 }
955 if (island.fill_expolygons_composite()) {
956 // They were split, thus store the unsplit "composite" expolygons into the region of perimeters.
957 LayerRegion &this_layer_region = *regions[region_id];
958 auto begin = uint32_t(this_layer_region.fill_expolygons_composite().size());
959 this_layer_region.m_fill_expolygons_composite.reserve(this_layer_region.fill_expolygons_composite().size() + fill_range.size());
960 std::move(fill_expolygons.begin() + *fill_range.begin(), fill_expolygons.begin() + *fill_range.end(), std::back_inserter(this_layer_region.m_fill_expolygons_composite));
961 this_layer_region.m_fill_expolygons_composite_bboxes.insert(this_layer_region.m_fill_expolygons_composite_bboxes.end(),
962 fill_expolygons_bboxes.begin() + *fill_range.begin(), fill_expolygons_bboxes.begin() + *fill_range.end());
963 island.fill_expolygons = ExPolygonRange(begin, uint32_t(this_layer_region.fill_expolygons_composite().size()));
964 } else {
965 // All expolygons are stored inside a single LayerRegion in a contiguous range.
966 island.fill_expolygons = ExPolygonRange(
967 map_expolygon_to_region_and_fill[*fill_range.begin()].fill_in_region_id,
968 map_expolygon_to_region_and_fill[*fill_range.end() - 1].fill_in_region_id + 1);
969 }
970 } else {
971 // Layer island is made of one fill region only.
972 island.fill_expolygons = fill_range;
973 island.fill_region_id = region_id;
974 }
975 }
976 };
977
978 // First sort into islands using exact fit.
979 // Traverse the slices in an increasing order of bounding box size, so that the islands inside another islands are tested first,
980 // so we can just test a point inside ExPolygon::contour and we may skip testing the holes.
981 auto point_inside_surface = [&lslices = this->lslices, &lslices_ex = this->lslices_ex](size_t lslice_idx, const Point &point) {
982 const BoundingBox &bbox = lslices_ex[lslice_idx].bbox;
983 return point.x() >= bbox.min.x() && point.x() < bbox.max.x() &&
984 point.y() >= bbox.min.y() && point.y() < bbox.max.y() &&
985 // Exact match: Don't just test whether a point is inside the outer contour of an island,
986 // test also whether the point is not inside some hole of the same expolygon.
987 // This is unfortunatelly necessary because the point may be inside an expolygon of one of this expolygon's hole
988 // and missed due to numerical issues.
989 lslices[lslice_idx].contains(point);
990 };
991 for (int lslice_idx = int(lslices_ex.size()) - 1; lslice_idx >= 0 && ! perimeter_slices_queue.empty(); -- lslice_idx)
992 for (auto it_source_slice = perimeter_slices_queue.begin(); it_source_slice != perimeter_slices_queue.end(); ++ it_source_slice)
993 if (point_inside_surface(lslice_idx, it_source_slice->second)) {
994 insert_into_island(lslice_idx, it_source_slice->first);
995 if (std::next(it_source_slice) != perimeter_slices_queue.end())
996 // Remove the current slice & point pair from the queue.
997 *it_source_slice = perimeter_slices_queue.back();
998 perimeter_slices_queue.pop_back();
999 break;
1000 }
1001 if (! perimeter_slices_queue.empty()) {
1002 // If the slice sample was not fitted into any slice using exact fit, try to find a closest island as a last resort.
1003 // This should be a rare event especially if the sample point was taken from infill or inner perimeter,
1004 // however we may land here for external perimeter only islands with fuzzy skin applied.
1005 // Check whether fuzzy skin was enabled and adjust the bounding box accordingly.
1006 const PrintConfig &print_config = this->object()->print()->config();
1007 const PrintRegionConfig &region_config = this_layer_region.region().config();
1008 const auto bbox_eps = scaled<coord_t>(
1009 EPSILON + print_config.gcode_resolution.value +
1010 (region_config.fuzzy_skin.value == FuzzySkinType::None ? 0. : region_config.fuzzy_skin_thickness.value
1011 //FIXME it looks as if Arachne could extend open lines by fuzzy_skin_point_dist, which does not seem right.
1012 + region_config.fuzzy_skin_point_dist.value));
1013 auto point_inside_surface_dist2 =
1014 [&lslices = this->lslices, &lslices_ex = this->lslices_ex, bbox_eps]
1015 (const size_t lslice_idx, const Point &point) {
1016 const BoundingBox &bbox = lslices_ex[lslice_idx].bbox;
1017 return
1018 point.x() < bbox.min.x() - bbox_eps || point.x() > bbox.max.x() + bbox_eps ||
1019 point.y() < bbox.min.y() - bbox_eps || point.y() > bbox.max.y() + bbox_eps ?
1020 std::numeric_limits<double>::max() :
1021 (lslices[lslice_idx].point_projection(point) - point).cast<double>().squaredNorm();
1022 };
1023 for (auto it_source_slice = perimeter_slices_queue.begin(); it_source_slice != perimeter_slices_queue.end(); ++ it_source_slice) {
1024 double d2min = std::numeric_limits<double>::max();
1025 int lslice_idx_min = -1;
1026 for (int lslice_idx = int(lslices_ex.size()) - 1; lslice_idx >= 0; -- lslice_idx)
1027 if (double d2 = point_inside_surface_dist2(lslice_idx, it_source_slice->second); d2 < d2min) {
1028 d2min = d2;
1029 lslice_idx_min = lslice_idx;
1030 }
1031 if (lslice_idx_min == -1) {
1032 // This should not happen, but Arachne seems to produce a perimeter point far outside its source contour.
1033 // As a last resort, find the closest source contours to the sample point.
1034 for (int lslice_idx = int(lslices_ex.size()) - 1; lslice_idx >= 0; -- lslice_idx)
1035 if (double d2 = (lslices[lslice_idx].point_projection(it_source_slice->second) - it_source_slice->second).cast<double>().squaredNorm(); d2 < d2min) {
1036 d2min = d2;
1037 lslice_idx_min = lslice_idx;
1038 }
1039 }
1040 assert(lslice_idx_min != -1);
1041 insert_into_island(lslice_idx_min, it_source_slice->first);
1042 }
1043 }
1044}
EIGEN_DEVICE_FUNC CastXpr< NewType >::Type cast() const
Definition CommonCwiseUnaryOps.h:62
bool empty() const
Definition Layer.hpp:55
T size() const
Definition Layer.hpp:56
bool expolygons_match(const ExPolygon &l, const ExPolygon &r)
Definition ExPolygon.cpp:342
IndexRange< uint32_t > ExPolygonRange
Definition Layer.hpp:66
std::vector< BoundingBox > BoundingBoxes
Definition BoundingBox.hpp:202
static constexpr const uint32_t fill_region_composite_id
Definition Layer.hpp:240

References Slic3r::PrintRegion::config(), Slic3r::ExPolygon::empty(), Slic3r::IndexRange< T >::empty(), Slic3r::ExtrusionEntityCollection::entities, EPSILON, Slic3r::expolygons_match(), Slic3r::LayerRegion::fill_expolygons(), Slic3r::LayerIsland::fill_expolygons, Slic3r::LayerRegion::fill_expolygons_composite(), Slic3r::LayerIsland::fill_expolygons_composite(), Slic3r::LayerIsland::fill_region_id, Slic3r::get_extents(), Slic3r::intersection_ex(), Slic3r::ExtrusionEntity::is_collection(), Slic3r::ExtrusionRole::is_external(), Slic3r::LayerRegion::m_fill_expolygons, Slic3r::LayerRegion::m_fill_expolygons_bboxes, Slic3r::LayerRegion::m_fill_expolygons_composite, Slic3r::LayerRegion::m_fill_expolygons_composite_bboxes, Slic3r::BoundingBoxBase< PointType, APointsType >::max, Slic3r::ExtrusionEntity::middle_point(), Slic3r::BoundingBoxBase< PointType, APointsType >::min, Slic3r::LayerRegion::perimeters(), Slic3r::LayerIsland::perimeters, Slic3r::PrintRegionConfig, Slic3r::LayerRegion::region(), Slic3r::ExtrusionEntity::role(), Slic3r::IndexRange< T >::size(), Slic3r::SurfaceCollection::size(), Slic3r::LayerRegion::slices(), Slic3r::SurfaceCollection::surfaces, Slic3r::LayerRegion::thin_fills(), and Slic3r::LayerIsland::thin_fills.

+ Here is the call graph for this function:

Friends And Related Symbol Documentation

◆ PrintObject

friend class PrintObject
friend

Member Data Documentation

◆ curled_lines

◆ height

◆ lower_layer

◆ lslice_indices_sorted_by_print_order

std::vector<size_t> Slic3r::Layer::lslice_indices_sorted_by_print_order
inherited

◆ lslices

◆ lslices_ex

◆ m_id

size_t Slic3r::Layer::m_id
privateinherited

◆ m_interface_id

size_t Slic3r::SupportLayer::m_interface_id
protected

Referenced by interface_id().

◆ m_object

PrintObject* Slic3r::Layer::m_object
privateinherited

◆ m_regions

◆ print_z

◆ slice_z

◆ support_fills

◆ support_islands

ExPolygons Slic3r::SupportLayer::support_islands

◆ support_islands_bboxes

BoundingBoxes Slic3r::SupportLayer::support_islands_bboxes

◆ upper_layer

Layer* Slic3r::Layer::upper_layer
inherited

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