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

#include <src/libslic3r/Print.hpp>

+ Inheritance diagram for Slic3r::PrintObject:
+ Collaboration diagram for Slic3r::PrintObject:

Public Types

using PrintObjectStepEnum = PrintObjectStep
 
typedef PrintState< PrintObjectStepEnum, COUNT > PrintObjectState
 
using Timestamp = uint64_t
 

Public Member Functions

const Vec3crdsize () const
 
const PrintObjectConfigconfig () const
 
auto layers () const
 
auto support_layers () const
 
const Transform3dtrafo () const
 
Transform3d trafo_centered () const
 
const PrintInstancesinstances () const
 
LayerPtrslayers ()
 
SupportLayerPtrssupport_layers ()
 
BoundingBox bounding_box () const
 
coord_t height () const
 
const Pointcenter_offset () const
 
bool has_brim () const
 
size_t total_layer_count () const
 
size_t layer_count () const
 
void clear_layers ()
 
const Layerget_layer (int idx) const
 
Layerget_layer (int idx)
 
const Layerget_layer_at_printz (coordf_t print_z) const
 
Layerget_layer_at_printz (coordf_t print_z)
 
const Layerget_layer_at_printz (coordf_t print_z, coordf_t epsilon) const
 
Layerget_layer_at_printz (coordf_t print_z, coordf_t epsilon)
 
const Layerget_first_layer_bellow_printz (coordf_t print_z, coordf_t epsilon) const
 
Layeradd_layer (int id, coordf_t height, coordf_t print_z, coordf_t slice_z)
 
size_t support_layer_count () const
 
void clear_support_layers ()
 
SupportLayerget_support_layer (int idx)
 
SupportLayeradd_support_layer (int id, int interface_id, coordf_t height, coordf_t print_z)
 
SupportLayerPtrs::iterator insert_support_layer (SupportLayerPtrs::iterator pos, size_t id, size_t interface_id, coordf_t height, coordf_t print_z, coordf_t slice_z)
 
void delete_support_layer (int idx)
 
const SlicingParametersslicing_parameters () const
 
size_t num_printing_regions () const throw ()
 
const PrintRegionprinting_region (size_t idx) const throw ()
 
std::vector< std::reference_wrapper< const PrintRegion > > all_regions () const
 
const PrintObjectRegionsshared_regions () const throw ()
 
bool has_support () const
 
bool has_raft () const
 
bool has_support_material () const
 
bool is_mm_painted () const
 
std::vector< unsigned int > object_extruders () const
 
void slice ()
 
std::vector< Polygonsslice_support_volumes (const ModelVolumeType model_volume_type) const
 
std::vector< Polygonsslice_support_blockers () const
 
std::vector< Polygonsslice_support_enforcers () const
 
void project_and_append_custom_facets (bool seam, EnforcerBlockerType type, std::vector< Polygons > &expolys) const
 
Printprint ()
 
const Printprint () const
 
bool is_step_done (PrintObjectStepEnum step) const
 
PrintStateBase::StateWithTimeStamp step_state_with_timestamp (PrintObjectStepEnum step) const
 
PrintStateBase::StateWithWarnings step_state_with_warnings (PrintObjectStepEnum step) const
 
auto last_completed_step () const
 
const ModelObjectmodel_object () const
 
ModelObjectmodel_object ()
 
ObjectID id () const
 
virtual Timestamp timestamp () const
 

Static Public Member Functions

static bool update_layer_height_profile (const ModelObject &model_object, const SlicingParameters &slicing_parameters, std::vector< coordf_t > &layer_height_profile)
 
static SlicingParameters slicing_parameters (const DynamicPrintConfig &full_config, const ModelObject &model_object, float object_max_z)
 

Static Public Attributes

static constexpr const size_t PrintObjectStepEnumSize
 

Protected Member Functions

bool set_started (PrintObjectStepEnum step)
 
PrintStateBase::TimeStamp set_done (PrintObjectStepEnum step)
 
bool invalidate_steps (StepTypeIterator step_begin, StepTypeIterator step_end)
 
bool invalidate_steps (std::initializer_list< PrintObjectStepEnum > il)
 
bool is_step_started_unguarded (PrintObjectStepEnum step) const
 
bool is_step_done_unguarded (PrintObjectStepEnum step) const
 
bool is_step_enabled_unguarded (PrintObjectStepEnum step) const
 
void enable_step_unguarded (PrintObjectStepEnum step, bool enable)
 
void enable_all_steps_unguarded (bool enable)
 
void finalize_impl ()
 
bool query_reset_dirty_step_unguarded (PrintObjectStepEnum step)
 
void active_step_add_warning (PrintStateBase::WarningLevel warning_level, const std::string &message, int message_id=0)
 
void throw_if_canceled ()
 
void status_update_warnings (PrintBase *print, int step, PrintStateBase::WarningLevel warning_level, const std::string &message)
 
void set_new_unique_id ()
 
void set_invalid_id ()
 
void copy_id (const ObjectBase &rhs)
 
virtual void assign_new_unique_ids_recursive ()
 

Static Protected Member Functions

static std::mutex & state_mutex (PrintBase *print)
 
static std::function< void()> cancel_callback (PrintBase *print)
 

Protected Attributes

friend PrintType
 
Printm_print
 
ModelObjectm_model_object
 

Private Types

typedef PrintObjectBaseWithState< Print, PrintObjectStep, posCountInherited
 

Private Member Functions

 PrintObject (Print *print, ModelObject *model_object, const Transform3d &trafo, PrintInstances &&instances)
 
 ~PrintObject () override
 
void config_apply (const ConfigBase &other, bool ignore_nonexistent=false)
 
void config_apply_only (const ConfigBase &other, const t_config_option_keys &keys, bool ignore_nonexistent=false)
 
PrintBase::ApplyStatus set_instances (PrintInstances &&instances)
 
bool invalidate_step (PrintObjectStep step)
 
bool invalidate_all_steps ()
 
bool invalidate_state_by_config_options (const ConfigOptionResolver &old_config, const ConfigOptionResolver &new_config, const std::vector< t_config_option_key > &opt_keys)
 
void update_slicing_parameters ()
 
void cleanup ()
 
void make_perimeters ()
 
void prepare_infill ()
 
void clear_fills ()
 
void infill ()
 
void ironing ()
 
void generate_support_spots ()
 
void generate_support_material ()
 
void estimate_curled_extrusions ()
 
void slice_volumes ()
 
void detect_surfaces_type ()
 
void process_external_surfaces ()
 
void discover_vertical_shells ()
 
void bridge_over_infill ()
 
void clip_fill_surfaces ()
 
void discover_horizontal_shells ()
 
void combine_infill ()
 
void _generate_support_material ()
 
std::pair< FillAdaptive::OctreePtr, FillAdaptive::OctreePtrprepare_adaptive_infill_data (const std::vector< std::pair< const Surface *, float > > &surfaces_w_bottom_z) const
 
FillLightning::GeneratorPtr prepare_lightning_infill_data ()
 
template<class Archive >
void serialize (Archive &ar)
 

Static Private Member Functions

static PrintObjectConfig object_config_from_model_object (const PrintObjectConfig &default_object_config, const ModelObject &object, size_t num_extruders)
 
static ObjectID generate_new_id ()
 
template<class Archive >
static void load_and_construct (Archive &ar, cereal::construct< ObjectBase > &construct)
 

Private Attributes

Vec3crd m_size
 
PrintObjectConfig m_config
 
Transform3d m_trafo = Transform3d::Identity()
 
std::vector< PrintInstancem_instances
 
Point m_center_offset
 
PrintObjectRegionsm_shared_regions { nullptr }
 
SlicingParameters m_slicing_params
 
LayerPtrs m_layers
 
SupportLayerPtrs m_support_layers
 
bool m_typed_slices = false
 
std::pair< FillAdaptive::OctreePtr, FillAdaptive::OctreePtrm_adaptive_fill_octrees
 
FillLightning::GeneratorPtr m_lightning_generator
 
PrintState< PrintObjectStepEnum, COUNT > m_state
 
ObjectID m_id
 

Static Private Attributes

static size_t s_last_id = 0
 

Friends

class Print
 
class PrintBaseWithState< PrintStep, psCount >
 

Detailed Description

Member Typedef Documentation

◆ Inherited

◆ PrintObjectState

typedef PrintState<PrintObjectStepEnum, COUNT> Slic3r::PrintObjectBaseWithState< Print , PrintObjectStep , COUNT >::PrintObjectState
inherited

◆ PrintObjectStepEnum

using Slic3r::PrintObjectBaseWithState< Print , PrintObjectStep , COUNT >::PrintObjectStepEnum = PrintObjectStep
inherited

◆ Timestamp

Constructor & Destructor Documentation

◆ PrintObject()

Slic3r::PrintObject::PrintObject ( Print print,
ModelObject model_object,
const Transform3d trafo,
PrintInstances &&  instances 
)
private
97 :
100{
101 // Compute centering offet to be applied to our meshes so that we work with smaller coordinates
102 // requiring less bits to represent Clipper coordinates.
103
104 // Snug bounding box of a rotated and scaled object by the 1st instantion, without the instance translation applied.
105 // All the instances share the transformation matrix with the exception of translation in XY and rotation by Z,
106 // therefore a bounding box from 1st instance of a ModelObject is good enough for calculating the object center,
107 // snug height and an approximate bounding box in XY.
108 BoundingBoxf3 bbox = model_object->raw_bounding_box();
109 Vec3d bbox_center = bbox.center();
110 // We may need to rotate the bbox / bbox_center from the original instance to the current instance.
111 double z_diff = Geometry::rotation_diff_z(model_object->instances.front()->get_matrix(), instances.front().model_instance->get_matrix());
112 if (std::abs(z_diff) > EPSILON) {
113 auto z_rot = Eigen::AngleAxisd(z_diff, Vec3d::UnitZ());
114 bbox = bbox.transformed(Transform3d(z_rot));
115 bbox_center = (z_rot * bbox_center).eval();
116 }
117
118 // Center of the transformed mesh (without translation).
119 m_center_offset = Point::new_scale(bbox_center.x(), bbox_center.y());
120 // Size of the transformed mesh. This bounding may not be snug in XY plane, but it is snug in Z.
121 m_size = (bbox.size() * (1. / SCALING_FACTOR)).cast<coord_t>();
123
124 this->set_instances(std::move(instances));
125}
ModelInstancePtrs instances
Definition Model.hpp:334
double max_z() const
Definition Model.cpp:904
const BoundingBoxf3 & raw_bounding_box() const
Definition Model.cpp:1024
const ModelObject * model_object() const
Definition PrintBase.hpp:362
PrintObjectBaseWithState(Print *print, ModelObject *model_object)
Definition PrintBase.hpp:759
const PrintInstances & instances() const
Definition Print.hpp:253
Vec3crd m_size
Definition Print.hpp:395
const Transform3d & trafo() const
Definition Print.hpp:249
Point m_center_offset
Definition Print.hpp:403
PrintBase::ApplyStatus set_instances(PrintInstances &&instances)
Definition PrintObject.cpp:127
Transform3d m_trafo
Definition Print.hpp:398
AngleAxis< double > AngleAxisd
Definition AngleAxis.h:160
static constexpr double EPSILON
Definition libslic3r.h:51
int32_t coord_t
Definition libslic3r.h:39
static constexpr double SCALING_FACTOR
Definition libslic3r.h:57
double rotation_diff_z(const Transform3d &trafo_from, const Transform3d &trafo_to)
Definition Geometry.cpp:712
Eigen::Transform< double, 3, Eigen::Affine, Eigen::DontAlign > Transform3d
Definition Point.hpp:81
Eigen::Matrix< double, 3, 1, Eigen::DontAlign > Vec3d
Definition Point.hpp:52

References Slic3r::BoundingBox3Base< PointType >::center(), EPSILON, Slic3r::ModelObject::instances, instances(), m_center_offset, m_size, Slic3r::ModelObject::max_z(), Slic3r::PrintObjectBase::model_object(), Slic3r::ModelObject::raw_bounding_box(), Slic3r::Geometry::rotation_diff_z(), SCALING_FACTOR, set_instances(), Slic3r::BoundingBox3Base< PointType >::size(), and Slic3r::BoundingBoxf3::transformed().

+ Here is the call graph for this function:

Member Function Documentation

◆ ~PrintObject()

Slic3r::PrintObject::~PrintObject ( )
inlineoverrideprivate
344 {
346 delete m_shared_regions;
347 clear_layers();
349 }
void clear_layers()
Definition PrintObject.cpp:592
void clear_support_layers()
Definition PrintObject.cpp:605
PrintObjectRegions * m_shared_regions
Definition Print.hpp:407
size_t m_ref_cnt
Definition Print.hpp:235

References clear_layers(), clear_support_layers(), Slic3r::PrintObjectRegions::m_ref_cnt, and m_shared_regions.

+ Here is the call graph for this function:

◆ _generate_support_material()

void Slic3r::PrintObject::_generate_support_material ( )
private
2868{
2869 if (this->has_support() && (m_config.support_material_style == smsTree || m_config.support_material_style == smsOrganic)) {
2870 fff_tree_support_generate(*this, std::function<void()>([this](){ this->throw_if_canceled(); }));
2871 } else {
2872 // If support style is set to Organic however only raft will be built but no support,
2873 // build snug raft instead.
2874 PrintObjectSupportMaterial support_material(this, m_slicing_params);
2875 support_material.generate(*this);
2876 }
2877}
SlicingParameters m_slicing_params
Definition Print.hpp:409
bool has_support() const
Definition Print.hpp:318
PrintObjectConfig m_config
Definition Print.hpp:396
void fff_tree_support_generate(PrintObject &print_object, std::function< void()> throw_on_cancel)
Definition TreeSupport.cpp:3618
@ smsOrganic
Definition PrintConfig.hpp:90
@ smsTree
Definition PrintConfig.hpp:90

References Slic3r::fff_tree_support_generate(), Slic3r::PrintObjectSupportMaterial::generate(), Slic3r::smsOrganic, and Slic3r::smsTree.

+ Here is the call graph for this function:

◆ active_step_add_warning()

void Slic3r::PrintObjectBaseWithState< Print , PrintObjectStep , COUNT >::active_step_add_warning ( PrintStateBase::WarningLevel  warning_level,
const std::string &  message,
int  message_id = 0 
)
inlineprotectedinherited
794 {
795 std::pair<PrintObjectStepEnum, bool> active_step = m_state.active_step_add_warning(warning_level, message, message_id, PrintObjectBase::state_mutex(m_print));
796 if (active_step.second)
797 this->status_update_warnings(m_print, static_cast<int>(active_step.first), warning_level, message);
798 }
void status_update_warnings(PrintBase *print, int step, PrintStateBase::WarningLevel warning_level, const std::string &message)
Definition PrintBase.cpp:120
PrintState< PrintObjectStepEnum, COUNT > m_state
Definition PrintBase.hpp:809
std::pair< StepType, bool > active_step_add_warning(PrintStateBase::WarningLevel warning_level, const std::string &message, int message_id, std::mutex &mtx)
Definition PrintBase.hpp:321

◆ add_layer()

Layer * Slic3r::PrintObject::add_layer ( int  id,
coordf_t  height,
coordf_t  print_z,
coordf_t  slice_z 
)
600{
601 m_layers.emplace_back(new Layer(id, this, height, print_z, slice_z));
602 return m_layers.back();
603}
coord_t height() const
Definition Print.hpp:264
LayerPtrs m_layers
Definition Print.hpp:410

◆ add_support_layer()

SupportLayer * Slic3r::PrintObject::add_support_layer ( int  id,
int  interface_id,
coordf_t  height,
coordf_t  print_z 
)
613{
614 m_support_layers.emplace_back(new SupportLayer(id, interface_id, this, height, print_z, -1));
615 return m_support_layers.back();
616}
SupportLayerPtrs m_support_layers
Definition Print.hpp:411

◆ all_regions()

std::vector< std::reference_wrapper< const PrintRegion > > Slic3r::PrintObject::all_regions ( ) const
150{
151 std::vector<std::reference_wrapper<const PrintRegion>> out;
152 out.reserve(m_shared_regions->all_regions.size());
153 for (const std::unique_ptr<Slic3r::PrintRegion> &region : m_shared_regions->all_regions)
154 out.emplace_back(*region.get());
155 return out;
156}
std::vector< std::reference_wrapper< const PrintRegion > > all_regions() const
Definition PrintObject.cpp:149
std::vector< std::unique_ptr< PrintRegion > > all_regions
Definition Print.hpp:214
constexpr auto get(span< E, S > s) -> decltype(s[N])
Definition span.hpp:590

References Slic3r::PrintObjectRegions::all_regions, and m_shared_regions.

◆ assign_new_unique_ids_recursive()

virtual void Slic3r::ObjectBase::assign_new_unique_ids_recursive ( )
inlineprotectedvirtualinherited

Reimplemented in Slic3r::Model, Slic3r::ModelObject, and Slic3r::ModelVolume.

79{ this->set_new_unique_id(); }
void set_new_unique_id()
Definition ObjectID.hpp:73

References Slic3r::ObjectBase::set_new_unique_id().

+ Here is the call graph for this function:

◆ bounding_box()

BoundingBox Slic3r::PrintObject::bounding_box ( ) const
inline
261{ return BoundingBox(Point(- m_size.x() / 2, - m_size.y() / 2), Point(m_size.x() / 2, m_size.y() / 2)); }
Kernel::Point_2 Point
Definition point_areas.cpp:20

References m_size.

Referenced by Slic3r::SeamPlacer::init().

+ Here is the caller graph for this function:

◆ bridge_over_infill()

void Slic3r::PrintObject::bridge_over_infill ( )
private
1630{
1631 BOOST_LOG_TRIVIAL(info) << "Bridge over infill - Start" << log_memory_info();
1632
1633 struct CandidateSurface
1634 {
1635 CandidateSurface(const Surface *original_surface,
1636 int layer_index,
1637 Polygons new_polys,
1638 const LayerRegion *region,
1639 double bridge_angle)
1640 : original_surface(original_surface)
1641 , layer_index(layer_index)
1642 , new_polys(new_polys)
1643 , region(region)
1645 {}
1646 const Surface *original_surface;
1647 int layer_index;
1648 Polygons new_polys;
1649 const LayerRegion *region;
1650 double bridge_angle;
1651 };
1652
1653 std::map<size_t, std::vector<CandidateSurface>> surfaces_by_layer;
1654
1655 // SECTION to gather and filter surfaces for expanding, and then cluster them by layer
1656 {
1657 tbb::concurrent_vector<CandidateSurface> candidate_surfaces;
1658 tbb::parallel_for(tbb::blocked_range<size_t>(0, this->layers().size()), [po = static_cast<const PrintObject *>(this),
1659 &candidate_surfaces](tbb::blocked_range<size_t> r) {
1660 PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
1661 for (size_t lidx = r.begin(); lidx < r.end(); lidx++) {
1662 const Layer *layer = po->get_layer(lidx);
1663 if (layer->lower_layer == nullptr) {
1664 continue;
1665 }
1666 double spacing = layer->regions().front()->flow(frSolidInfill).scaled_spacing();
1667 // unsupported area will serve as a filter for polygons worth bridging.
1668 Polygons unsupported_area;
1669 Polygons lower_layer_solids;
1670 for (const LayerRegion *region : layer->lower_layer->regions()) {
1671 Polygons fill_polys = to_polygons(region->fill_expolygons());
1672 // initially consider the whole layer unsupported, but also gather solid layers to later cut off supported parts
1673 unsupported_area.insert(unsupported_area.end(), fill_polys.begin(), fill_polys.end());
1674 for (const Surface &surface : region->fill_surfaces()) {
1675 if (surface.surface_type != stInternal || region->region().config().fill_density.value == 100) {
1676 Polygons p = to_polygons(surface.expolygon);
1677 lower_layer_solids.insert(lower_layer_solids.end(), p.begin(), p.end());
1678 }
1679 }
1680 }
1681 unsupported_area = closing(unsupported_area, float(SCALED_EPSILON));
1682 // By expanding the lower layer solids, we avoid making bridges from the tiny internal overhangs that are (very likely) supported by previous layer solids
1683 // NOTE that we cannot filter out polygons worth bridging by their area, because sometimes there is a very small internal island that will grow into large hole
1684 lower_layer_solids = shrink(lower_layer_solids, 1 * spacing); // first remove thin regions that will not support anything
1685 lower_layer_solids = expand(lower_layer_solids, (1 + 3) * spacing); // then expand back (opening), and further for parts supported by internal solids
1686 // By shrinking the unsupported area, we avoid making bridges from narrow ensuring region along perimeters.
1687 unsupported_area = shrink(unsupported_area, 3 * spacing);
1688 unsupported_area = diff(unsupported_area, lower_layer_solids);
1689
1690 for (const LayerRegion *region : layer->regions()) {
1691 SurfacesPtr region_internal_solids = region->fill_surfaces().filter_by_type(stInternalSolid);
1692 for (const Surface *s : region_internal_solids) {
1693 Polygons unsupported = intersection(to_polygons(s->expolygon), unsupported_area);
1694 // The following flag marks those surfaces, which overlap with unuspported area, but at least part of them is supported.
1695 // These regions can be filtered by area, because they for sure are touching solids on lower layers, and it does not make sense to bridge their tiny overhangs
1696 bool partially_supported = area(unsupported) < area(to_polygons(s->expolygon)) - EPSILON;
1697 if (!unsupported.empty() && (!partially_supported || area(unsupported) > 3 * 3 * spacing * spacing)) {
1698 Polygons worth_bridging = intersection(to_polygons(s->expolygon), expand(unsupported, 4 * spacing));
1699 // after we extracted the part worth briding, we go over the leftovers and merge the tiny ones back, to not brake the surface too much
1700 for (const Polygon& p : diff(to_polygons(s->expolygon), expand(worth_bridging, spacing))) {
1701 double area = p.area();
1702 if (area < spacing * scale_(12.0) && area > spacing * spacing) {
1703 worth_bridging.push_back(p);
1704 }
1705 }
1706 worth_bridging = intersection(closing(worth_bridging, float(SCALED_EPSILON)), s->expolygon);
1707 candidate_surfaces.push_back(CandidateSurface(s, lidx, worth_bridging, region, 0));
1708
1709#ifdef DEBUG_BRIDGE_OVER_INFILL
1710 debug_draw(std::to_string(lidx) + "_candidate_surface_" + std::to_string(area(s->expolygon)),
1711 to_lines(region->layer()->lslices), to_lines(s->expolygon), to_lines(worth_bridging),
1712 to_lines(unsupported_area));
1713#endif
1714#ifdef DEBUG_BRIDGE_OVER_INFILL
1715 debug_draw(std::to_string(lidx) + "_candidate_processing_" + std::to_string(area(unsupported)),
1716 to_lines(unsupported), to_lines(intersection(to_polygons(s->expolygon), expand(unsupported, 5 * spacing))),
1717 to_lines(diff(to_polygons(s->expolygon), expand(worth_bridging, spacing))),
1718 to_lines(unsupported_area));
1719#endif
1720 }
1721 }
1722 }
1723 }
1724 });
1725
1726 for (const CandidateSurface &c : candidate_surfaces) {
1727 surfaces_by_layer[c.layer_index].push_back(c);
1728 }
1729 }
1730
1731 // LIGHTNING INFILL SECTION - If lightning infill is used somewhere, we check the areas that are going to be bridges, and those that rely on the
1732 // lightning infill under them get expanded. This somewhat helps to ensure that most of the extrusions are anchored to the lightning infill at the ends.
1733 // It requires modifying this instance of print object in a specific way, so that we do not invalidate the pointers in our surfaces_by_layer structure.
1734 bool has_lightning_infill = false;
1735 for (size_t i = 0; i < this->num_printing_regions(); i++) {
1736 if (this->printing_region(i).config().fill_pattern == ipLightning) {
1737 has_lightning_infill = true;
1738 break;
1739 }
1740 }
1741 if (has_lightning_infill) {
1742 // Prepare backup data for the Layer Region infills. Before modfiyng the layer region, we backup its fill surfaces by moving! them into this map.
1743 // then a copy is created, modifiyed and passed to lightning infill generator. After generator is created, we restore the original state of the fills
1744 // again by moving the data from this map back to the layer regions. This ensures that pointers to surfaces stay valid.
1745 std::map<size_t, std::map<const LayerRegion *, SurfaceCollection>> backup_surfaces;
1746 for (size_t lidx = 0; lidx < this->layer_count(); lidx++) {
1747 backup_surfaces[lidx] = {};
1748 }
1749
1750 tbb::parallel_for(tbb::blocked_range<size_t>(0, this->layers().size()), [po = this, &backup_surfaces,
1751 &surfaces_by_layer](tbb::blocked_range<size_t> r) {
1752 PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
1753 for (size_t lidx = r.begin(); lidx < r.end(); lidx++) {
1754 if (surfaces_by_layer.find(lidx) == surfaces_by_layer.end())
1755 continue;
1756
1757 Layer *layer = po->get_layer(lidx);
1758 const Layer *lower_layer = layer->lower_layer;
1759 if (lower_layer == nullptr)
1760 continue;
1761
1762 Polygons lightning_fill;
1763 for (const LayerRegion *region : lower_layer->regions()) {
1764 if (region->region().config().fill_pattern == ipLightning) {
1765 Polygons lf = to_polygons(region->fill_surfaces().filter_by_type(stInternal));
1766 lightning_fill.insert(lightning_fill.end(), lf.begin(), lf.end());
1767 }
1768 }
1769
1770 if (lightning_fill.empty())
1771 continue;
1772
1773 for (LayerRegion *region : layer->regions()) {
1774 backup_surfaces[lidx][region] = std::move(
1775 region->m_fill_surfaces); // Make backup copy by move!! so that pointers in candidate surfaces stay valid
1776 // Copy the surfaces back, this will make copy, but we will later discard it anyway
1777 region->m_fill_surfaces = backup_surfaces[lidx][region];
1778 }
1779
1780 for (LayerRegion *region : layer->regions()) {
1781 ExPolygons sparse_infill = to_expolygons(region->fill_surfaces().filter_by_type(stInternal));
1782 ExPolygons solid_infill = to_expolygons(region->fill_surfaces().filter_by_type(stInternalSolid));
1783
1784 if (sparse_infill.empty()) {
1785 break;
1786 }
1787 for (const auto &surface : surfaces_by_layer[lidx]) {
1788 if (surface.region != region)
1789 continue;
1790 ExPolygons expansion = intersection_ex(sparse_infill, expand(surface.new_polys, scaled<float>(3.0)));
1791 solid_infill.insert(solid_infill.end(), expansion.begin(), expansion.end());
1792 }
1793
1794 solid_infill = union_safety_offset_ex(solid_infill);
1795 sparse_infill = diff_ex(sparse_infill, solid_infill);
1796
1797 region->m_fill_surfaces.remove_types({stInternalSolid, stInternal});
1798 for (const ExPolygon &ep : solid_infill) {
1799 region->m_fill_surfaces.surfaces.emplace_back(stInternalSolid, ep);
1800 }
1801 for (const ExPolygon &ep : sparse_infill) {
1802 region->m_fill_surfaces.surfaces.emplace_back(stInternal, ep);
1803 }
1804 }
1805 }
1806 });
1807
1808 // Use the modified surfaces to generate expanded lightning anchors
1810
1811 // And now restore carefully the original surfaces, again using move to avoid reallocation and preserving the validity of the
1812 // pointers in surface candidates
1813 for (size_t lidx = 0; lidx < this->layer_count(); lidx++) {
1814 Layer *layer = this->get_layer(lidx);
1815 for (LayerRegion *region : layer->regions()) {
1816 if (backup_surfaces[lidx].find(region) != backup_surfaces[lidx].end()) {
1817 region->m_fill_surfaces = std::move(backup_surfaces[lidx][region]);
1818 }
1819 }
1820 }
1821 }
1822
1823 std::map<size_t, Polylines> infill_lines;
1824 // SECTION to generate infill polylines
1825 {
1826 std::vector<std::pair<const Surface *, float>> surfaces_w_bottom_z;
1827 for (const auto &pair : surfaces_by_layer) {
1828 for (const CandidateSurface &c : pair.second) {
1829 surfaces_w_bottom_z.emplace_back(c.original_surface, c.region->m_layer->bottom_z());
1830 }
1831 }
1832
1833 this->m_adaptive_fill_octrees = this->prepare_adaptive_infill_data(surfaces_w_bottom_z);
1834
1835 std::vector<size_t> layers_to_generate_infill;
1836 for (const auto &pair : surfaces_by_layer) {
1837 assert(pair.first > 0);
1838 infill_lines[pair.first - 1] = {};
1839 layers_to_generate_infill.push_back(pair.first - 1);
1840 }
1841
1842 tbb::parallel_for(tbb::blocked_range<size_t>(0, layers_to_generate_infill.size()), [po = static_cast<const PrintObject *>(this),
1843 &layers_to_generate_infill,
1844 &infill_lines](tbb::blocked_range<size_t> r) {
1845 PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
1846 for (size_t job_idx = r.begin(); job_idx < r.end(); job_idx++) {
1847 size_t lidx = layers_to_generate_infill[job_idx];
1848 infill_lines.at(
1849 lidx) = po->get_layer(lidx)->generate_sparse_infill_polylines_for_anchoring(po->m_adaptive_fill_octrees.first.get(),
1850 po->m_adaptive_fill_octrees.second.get(),
1851 po->m_lightning_generator.get());
1852 }
1853 });
1854#ifdef DEBUG_BRIDGE_OVER_INFILL
1855 for (const auto &il : infill_lines) {
1856 debug_draw(std::to_string(il.first) + "_infill_lines", to_lines(get_layer(il.first)->lslices), to_lines(il.second), {}, {});
1857 }
1858#endif
1859 }
1860
1861 // cluster layers by depth needed for thick bridges. Each cluster is to be processed by single thread sequentially, so that bridges cannot appear one on another
1862 std::vector<std::vector<size_t>> clustered_layers_for_threads;
1863 float target_flow_height_factor = 0.9f;
1864 {
1865 std::vector<size_t> layers_with_candidates;
1866 std::map<size_t, Polygons> layer_area_covered_by_candidates;
1867 for (const auto& pair : surfaces_by_layer) {
1868 layers_with_candidates.push_back(pair.first);
1869 layer_area_covered_by_candidates[pair.first] = {};
1870 }
1871
1872 // prepare inflated filter for each candidate on each layer. layers will be put into single thread cluster if they are close to each other (z-axis-wise)
1873 // and if the inflated AABB polygons overlap somewhere
1874 tbb::parallel_for(tbb::blocked_range<size_t>(0, layers_with_candidates.size()), [&layers_with_candidates, &surfaces_by_layer,
1875 &layer_area_covered_by_candidates](
1876 tbb::blocked_range<size_t> r) {
1877 PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
1878 for (size_t job_idx = r.begin(); job_idx < r.end(); job_idx++) {
1879 size_t lidx = layers_with_candidates[job_idx];
1880 for (const auto &candidate : surfaces_by_layer.at(lidx)) {
1881 Polygon candiate_inflated_aabb = get_extents(candidate.new_polys).inflated(scale_(7)).polygon();
1882 layer_area_covered_by_candidates.at(lidx) = union_(layer_area_covered_by_candidates.at(lidx),
1883 Polygons{candiate_inflated_aabb});
1884 }
1885 }
1886 });
1887
1888 // note: surfaces_by_layer is ordered map
1889 for (auto pair : surfaces_by_layer) {
1890 if (clustered_layers_for_threads.empty() ||
1891 this->get_layer(clustered_layers_for_threads.back().back())->print_z <
1892 this->get_layer(pair.first)->print_z -
1893 this->get_layer(pair.first)->regions()[0]->bridging_flow(frSolidInfill, true).height() * target_flow_height_factor -
1894 EPSILON ||
1895 intersection(layer_area_covered_by_candidates[clustered_layers_for_threads.back().back()],
1896 layer_area_covered_by_candidates[pair.first])
1897 .empty()) {
1898 clustered_layers_for_threads.push_back({pair.first});
1899 } else {
1900 clustered_layers_for_threads.back().push_back(pair.first);
1901 }
1902 }
1903
1904#ifdef DEBUG_BRIDGE_OVER_INFILL
1905 std::cout << "BRIDGE OVER INFILL CLUSTERED LAYERS FOR SINGLE THREAD" << std::endl;
1906 for (auto cluster : clustered_layers_for_threads) {
1907 std::cout << "CLUSTER: ";
1908 for (auto l : cluster) {
1909 std::cout << l << " ";
1910 }
1911 std::cout << std::endl;
1912 }
1913#endif
1914 }
1915
1916 // LAMBDA to gather areas with sparse infill deep enough that we can fit thick bridges there.
1917 auto gather_areas_w_depth = [target_flow_height_factor](const PrintObject *po, int lidx, float target_flow_height) {
1918 // Gather layers sparse infill areas, to depth defined by used bridge flow
1919 ExPolygons layers_sparse_infill{};
1920 ExPolygons not_sparse_infill{};
1921 double bottom_z = po->get_layer(lidx)->print_z - target_flow_height * target_flow_height_factor - EPSILON;
1922 for (int i = int(lidx) - 1; i >= 0; --i) {
1923 // Stop iterating if layer is lower than bottom_z and at least one iteration was made
1924 const Layer *layer = po->get_layer(i);
1925 if (layer->print_z < bottom_z && i < int(lidx) - 1)
1926 break;
1927
1928 for (const LayerRegion *region : layer->regions()) {
1929 bool has_low_density = region->region().config().fill_density.value < 100;
1930 for (const Surface &surface : region->fill_surfaces()) {
1931 if ((surface.surface_type == stInternal && has_low_density) || surface.surface_type == stInternalVoid ) {
1932 layers_sparse_infill.push_back(surface.expolygon);
1933 } else {
1934 not_sparse_infill.push_back(surface.expolygon);
1935 }
1936 }
1937 }
1938 }
1939 layers_sparse_infill = union_ex(layers_sparse_infill);
1940 layers_sparse_infill = closing_ex(layers_sparse_infill, float(SCALED_EPSILON));
1941 not_sparse_infill = union_ex(not_sparse_infill);
1942 not_sparse_infill = closing_ex(not_sparse_infill, float(SCALED_EPSILON));
1943 return diff(layers_sparse_infill, not_sparse_infill);
1944 };
1945
1946 // LAMBDA do determine optimal bridging angle
1947 auto determine_bridging_angle = [](const Polygons &bridged_area, const Lines &anchors, InfillPattern dominant_pattern) {
1948 AABBTreeLines::LinesDistancer<Line> lines_tree(anchors);
1949
1950 std::map<double, int> counted_directions;
1951 for (const Polygon &p : bridged_area) {
1952 double acc_distance = 0;
1953 for (int point_idx = 0; point_idx < int(p.points.size()) - 1; ++point_idx) {
1954 Vec2d start = p.points[point_idx].cast<double>();
1955 Vec2d next = p.points[point_idx + 1].cast<double>();
1956 Vec2d v = next - start; // vector from next to current
1957 double dist_to_next = v.norm();
1958 acc_distance += dist_to_next;
1959 if (acc_distance > scaled(2.0)) {
1960 acc_distance = 0.0;
1961 v.normalize();
1962 int lines_count = int(std::ceil(dist_to_next / scaled(2.0)));
1963 float step_size = dist_to_next / lines_count;
1964 for (int i = 0; i < lines_count; ++i) {
1965 Point a = (start + v * (i * step_size)).cast<coord_t>();
1966 auto [distance, index, p] = lines_tree.distance_from_lines_extra<false>(a);
1967 double angle = lines_tree.get_line(index).orientation();
1968 if (angle > PI) {
1969 angle -= PI;
1970 }
1971 angle += PI * 0.5;
1972 counted_directions[angle]++;
1973 }
1974 }
1975 }
1976 }
1977
1978 std::pair<double, int> best_dir{0, 0};
1979 // sliding window accumulation
1980 for (const auto &dir : counted_directions) {
1981 int score_acc = 0;
1982 double dir_acc = 0;
1983 double window_start_angle = dir.first - PI * 0.1;
1984 double window_end_angle = dir.first + PI * 0.1;
1985 for (auto dirs_window = counted_directions.lower_bound(window_start_angle);
1986 dirs_window != counted_directions.upper_bound(window_end_angle); dirs_window++) {
1987 dir_acc += dirs_window->first * dirs_window->second;
1988 score_acc += dirs_window->second;
1989 }
1990 // current span of directions is 0.5 PI to 1.5 PI (due to the aproach.). Edge values should also account for the
1991 // opposite direction.
1992 if (window_start_angle < 0.5 * PI) {
1993 for (auto dirs_window = counted_directions.lower_bound(1.5 * PI - (0.5 * PI - window_start_angle));
1994 dirs_window != counted_directions.end(); dirs_window++) {
1995 dir_acc += dirs_window->first * dirs_window->second;
1996 score_acc += dirs_window->second;
1997 }
1998 }
1999 if (window_start_angle > 1.5 * PI) {
2000 for (auto dirs_window = counted_directions.begin();
2001 dirs_window != counted_directions.upper_bound(window_start_angle - 1.5 * PI); dirs_window++) {
2002 dir_acc += dirs_window->first * dirs_window->second;
2003 score_acc += dirs_window->second;
2004 }
2005 }
2006
2007 if (score_acc > best_dir.second) {
2008 best_dir = {dir_acc / score_acc, score_acc};
2009 }
2010 }
2011 double bridging_angle = best_dir.first;
2012 if (bridging_angle == 0) {
2013 bridging_angle = 0.001;
2014 }
2015 switch (dominant_pattern) {
2016 case ipHilbertCurve: bridging_angle += 0.25 * PI; break;
2017 case ipOctagramSpiral: bridging_angle += (1.0 / 16.0) * PI; break;
2018 default: break;
2019 }
2020
2021 return bridging_angle;
2022 };
2023
2024 // LAMBDA that will fill given polygons with lines, exapand the lines to the nearest anchor, and reconstruct polygons from the newly
2025 // generated lines
2026 auto construct_anchored_polygon = [](Polygons bridged_area, Lines anchors, const Flow &bridging_flow, double bridging_angle) {
2027 auto lines_rotate = [](Lines &lines, double cos_angle, double sin_angle) {
2028 for (Line &l : lines) {
2029 double ax = double(l.a.x());
2030 double ay = double(l.a.y());
2031 l.a.x() = coord_t(round(cos_angle * ax - sin_angle * ay));
2032 l.a.y() = coord_t(round(cos_angle * ay + sin_angle * ax));
2033 double bx = double(l.b.x());
2034 double by = double(l.b.y());
2035 l.b.x() = coord_t(round(cos_angle * bx - sin_angle * by));
2036 l.b.y() = coord_t(round(cos_angle * by + sin_angle * bx));
2037 }
2038 };
2039
2040 auto segments_overlap = [](coord_t alow, coord_t ahigh, coord_t blow, coord_t bhigh) {
2041 return (alow >= blow && alow <= bhigh) || (ahigh >= blow && ahigh <= bhigh) || (blow >= alow && blow <= ahigh) ||
2042 (bhigh >= alow && bhigh <= ahigh);
2043 };
2044
2045 Polygons expanded_bridged_area{};
2046 double aligning_angle = -bridging_angle + PI * 0.5;
2047 {
2048 polygons_rotate(bridged_area, aligning_angle);
2049 lines_rotate(anchors, cos(aligning_angle), sin(aligning_angle));
2050 BoundingBox bb_x = get_extents(bridged_area);
2051 BoundingBox bb_y = get_extents(anchors);
2052
2053 const size_t n_vlines = (bb_x.max.x() - bb_x.min.x() + bridging_flow.scaled_spacing() - 1) / bridging_flow.scaled_spacing();
2054 std::vector<Line> vertical_lines(n_vlines);
2055 for (size_t i = 0; i < n_vlines; i++) {
2056 coord_t x = bb_x.min.x() + i * bridging_flow.scaled_spacing();
2057 coord_t y_min = bb_y.min.y() - bridging_flow.scaled_spacing();
2058 coord_t y_max = bb_y.max.y() + bridging_flow.scaled_spacing();
2059 vertical_lines[i].a = Point{x, y_min};
2060 vertical_lines[i].b = Point{x, y_max};
2061 }
2062
2063 auto anchors_and_walls_tree = AABBTreeLines::LinesDistancer<Line>{std::move(anchors)};
2064 auto bridged_area_tree = AABBTreeLines::LinesDistancer<Line>{to_lines(bridged_area)};
2065
2066 std::vector<std::vector<Line>> polygon_sections(n_vlines);
2067 for (size_t i = 0; i < n_vlines; i++) {
2068 auto area_intersections = bridged_area_tree.intersections_with_line<true>(vertical_lines[i]);
2069 for (int intersection_idx = 0; intersection_idx < int(area_intersections.size()) - 1; intersection_idx++) {
2070 if (bridged_area_tree.outside(
2071 (area_intersections[intersection_idx].first + area_intersections[intersection_idx + 1].first) / 2) < 0) {
2072 polygon_sections[i].emplace_back(area_intersections[intersection_idx].first,
2073 area_intersections[intersection_idx + 1].first);
2074 }
2075 }
2076 auto anchors_intersections = anchors_and_walls_tree.intersections_with_line<true>(vertical_lines[i]);
2077
2078 for (Line &section : polygon_sections[i]) {
2079 auto maybe_below_anchor = std::upper_bound(anchors_intersections.rbegin(), anchors_intersections.rend(), section.a,
2080 [](const Point &a, const std::pair<Point, size_t> &b) {
2081 return a.y() > b.first.y();
2082 });
2083 if (maybe_below_anchor != anchors_intersections.rend()) {
2084 section.a = maybe_below_anchor->first;
2085 section.a.y() -= bridging_flow.scaled_width() * (0.5 + 0.5);
2086 }
2087
2088 auto maybe_upper_anchor = std::upper_bound(anchors_intersections.begin(), anchors_intersections.end(), section.b,
2089 [](const Point &a, const std::pair<Point, size_t> &b) {
2090 return a.y() < b.first.y();
2091 });
2092 if (maybe_upper_anchor != anchors_intersections.end()) {
2093 section.b = maybe_upper_anchor->first;
2094 section.b.y() += bridging_flow.scaled_width() * (0.5 + 0.5);
2095 }
2096 }
2097
2098 for (int section_idx = 0; section_idx < int(polygon_sections[i].size()) - 1; section_idx++) {
2099 Line &section_a = polygon_sections[i][section_idx];
2100 Line &section_b = polygon_sections[i][section_idx + 1];
2101 if (segments_overlap(section_a.a.y(), section_a.b.y(), section_b.a.y(), section_b.b.y())) {
2102 section_b.a = section_a.a.y() < section_b.a.y() ? section_a.a : section_b.a;
2103 section_b.b = section_a.b.y() < section_b.b.y() ? section_b.b : section_a.b;
2104 section_a.a = section_a.b;
2105 }
2106 }
2107
2108 polygon_sections[i].erase(std::remove_if(polygon_sections[i].begin(), polygon_sections[i].end(),
2109 [](const Line &s) { return s.a == s.b; }),
2110 polygon_sections[i].end());
2111 std::sort(polygon_sections[i].begin(), polygon_sections[i].end(),
2112 [](const Line &a, const Line &b) { return a.a.y() < b.b.y(); });
2113 }
2114
2115 // reconstruct polygon from polygon sections
2116 struct TracedPoly
2117 {
2118 Points lows;
2119 Points highs;
2120 };
2121
2122 std::vector<TracedPoly> current_traced_polys;
2123 for (const auto &polygon_slice : polygon_sections) {
2124 std::unordered_set<const Line *> used_segments;
2125 for (TracedPoly &traced_poly : current_traced_polys) {
2126 auto candidates_begin = std::upper_bound(polygon_slice.begin(), polygon_slice.end(), traced_poly.lows.back(),
2127 [](const Point &low, const Line &seg) { return seg.b.y() > low.y(); });
2128 auto candidates_end = std::upper_bound(polygon_slice.begin(), polygon_slice.end(), traced_poly.highs.back(),
2129 [](const Point &high, const Line &seg) { return seg.a.y() > high.y(); });
2130
2131 bool segment_added = false;
2132 for (auto candidate = candidates_begin; candidate != candidates_end && !segment_added; candidate++) {
2133 if (used_segments.find(&(*candidate)) != used_segments.end()) {
2134 continue;
2135 }
2136
2137 if ((traced_poly.lows.back() - candidate->a).cast<double>().squaredNorm() <
2138 36.0 * double(bridging_flow.scaled_spacing()) * bridging_flow.scaled_spacing()) {
2139 traced_poly.lows.push_back(candidate->a);
2140 } else {
2141 traced_poly.lows.push_back(traced_poly.lows.back() + Point{bridging_flow.scaled_spacing() / 2, 0});
2142 traced_poly.lows.push_back(candidate->a - Point{bridging_flow.scaled_spacing() / 2, 0});
2143 traced_poly.lows.push_back(candidate->a);
2144 }
2145
2146 if ((traced_poly.highs.back() - candidate->b).cast<double>().squaredNorm() <
2147 36.0 * double(bridging_flow.scaled_spacing()) * bridging_flow.scaled_spacing()) {
2148 traced_poly.highs.push_back(candidate->b);
2149 } else {
2150 traced_poly.highs.push_back(traced_poly.highs.back() + Point{bridging_flow.scaled_spacing() / 2, 0});
2151 traced_poly.highs.push_back(candidate->b - Point{bridging_flow.scaled_spacing() / 2, 0});
2152 traced_poly.highs.push_back(candidate->b);
2153 }
2154 segment_added = true;
2155 used_segments.insert(&(*candidate));
2156 }
2157
2158 if (!segment_added) {
2159 // Zero overlapping segments, we just close this polygon
2160 traced_poly.lows.push_back(traced_poly.lows.back() + Point{bridging_flow.scaled_spacing() / 2, 0});
2161 traced_poly.highs.push_back(traced_poly.highs.back() + Point{bridging_flow.scaled_spacing() / 2, 0});
2162 Polygon &new_poly = expanded_bridged_area.emplace_back(std::move(traced_poly.lows));
2163 new_poly.points.insert(new_poly.points.end(), traced_poly.highs.rbegin(), traced_poly.highs.rend());
2164 traced_poly.lows.clear();
2165 traced_poly.highs.clear();
2166 }
2167 }
2168
2169 current_traced_polys.erase(std::remove_if(current_traced_polys.begin(), current_traced_polys.end(),
2170 [](const TracedPoly &tp) { return tp.lows.empty(); }),
2171 current_traced_polys.end());
2172
2173 for (const auto &segment : polygon_slice) {
2174 if (used_segments.find(&segment) == used_segments.end()) {
2175 TracedPoly &new_tp = current_traced_polys.emplace_back();
2176 new_tp.lows.push_back(segment.a - Point{bridging_flow.scaled_spacing() / 2, 0});
2177 new_tp.lows.push_back(segment.a);
2178 new_tp.highs.push_back(segment.b - Point{bridging_flow.scaled_spacing() / 2, 0});
2179 new_tp.highs.push_back(segment.b);
2180 }
2181 }
2182 }
2183
2184 // add not closed polys
2185 for (TracedPoly &traced_poly : current_traced_polys) {
2186 Polygon &new_poly = expanded_bridged_area.emplace_back(std::move(traced_poly.lows));
2187 new_poly.points.insert(new_poly.points.end(), traced_poly.highs.rbegin(), traced_poly.highs.rend());
2188 }
2189 expanded_bridged_area = union_safety_offset(expanded_bridged_area);
2190 }
2191
2192 polygons_rotate(expanded_bridged_area, -aligning_angle);
2193 return expanded_bridged_area;
2194 };
2195
2196 tbb::parallel_for(tbb::blocked_range<size_t>(0, clustered_layers_for_threads.size()), [po = static_cast<const PrintObject *>(this),
2197 target_flow_height_factor, &surfaces_by_layer,
2198 &clustered_layers_for_threads,
2199 gather_areas_w_depth, &infill_lines,
2200 determine_bridging_angle,
2201 construct_anchored_polygon](
2202 tbb::blocked_range<size_t> r) {
2203 PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
2204 for (size_t cluster_idx = r.begin(); cluster_idx < r.end(); cluster_idx++) {
2205 for (size_t job_idx = 0; job_idx < clustered_layers_for_threads[cluster_idx].size(); job_idx++) {
2206 size_t lidx = clustered_layers_for_threads[cluster_idx][job_idx];
2207 const Layer *layer = po->get_layer(lidx);
2208 // this thread has exclusive access to all surfaces in layers enumerated in
2209 // clustered_layers_for_threads[cluster_idx]
2210
2211 // Presort the candidate polygons. This will help choose the same angle for neighbournig surfaces, that
2212 // would otherwise compete over anchoring sparse infill lines, leaving one area unachored
2213 std::sort(surfaces_by_layer[lidx].begin(), surfaces_by_layer[lidx].end(),
2214 [](const CandidateSurface &left, const CandidateSurface &right) {
2215 auto a = get_extents(left.new_polys);
2216 auto b = get_extents(right.new_polys);
2217
2218 if (a.min.x() == b.min.x()) {
2219 return a.min.y() < b.min.y();
2220 };
2221 return a.min.x() < b.min.x();
2222 });
2223 if (surfaces_by_layer[lidx].size() > 2) {
2224 Vec2d origin = get_extents(surfaces_by_layer[lidx].front().new_polys).max.cast<double>();
2225 std::stable_sort(surfaces_by_layer[lidx].begin() + 1, surfaces_by_layer[lidx].end(),
2226 [origin](const CandidateSurface &left, const CandidateSurface &right) {
2227 auto a = get_extents(left.new_polys);
2228 auto b = get_extents(right.new_polys);
2229
2230 return (origin - a.min.cast<double>()).squaredNorm() <
2231 (origin - b.min.cast<double>()).squaredNorm();
2232 });
2233 }
2234
2235 // Gather deep infill areas, where thick bridges fit
2236 coordf_t spacing = surfaces_by_layer[lidx].front().region->bridging_flow(frSolidInfill, true).scaled_spacing();
2237 coordf_t target_flow_height = surfaces_by_layer[lidx].front().region->bridging_flow(frSolidInfill, true).height() *
2238 target_flow_height_factor;
2239 Polygons deep_infill_area = gather_areas_w_depth(po, lidx, target_flow_height);
2240
2241 {
2242 // Now also remove area that has been already filled on lower layers by bridging expansion - For this
2243 // reason we did the clustering of layers per thread.
2244 Polygons filled_polyons_on_lower_layers;
2245 double bottom_z = layer->print_z - target_flow_height - EPSILON;
2246 if (job_idx > 0) {
2247 for (int lower_job_idx = job_idx - 1; lower_job_idx >= 0; lower_job_idx--) {
2248 size_t lower_layer_idx = clustered_layers_for_threads[cluster_idx][lower_job_idx];
2249 const Layer *lower_layer = po->get_layer(lower_layer_idx);
2250 if (lower_layer->print_z >= bottom_z) {
2251 for (const auto &c : surfaces_by_layer[lower_layer_idx]) {
2252 filled_polyons_on_lower_layers.insert(filled_polyons_on_lower_layers.end(), c.new_polys.begin(),
2253 c.new_polys.end());
2254 }
2255 } else {
2256 break;
2257 }
2258 }
2259 }
2260 deep_infill_area = diff(deep_infill_area, filled_polyons_on_lower_layers);
2261 }
2262
2263 deep_infill_area = expand(deep_infill_area, spacing * 1.5);
2264
2265 // Now gather expansion polygons - internal infill on current layer, from which we can cut off anchors
2266 Polygons lightning_area;
2267 Polygons expansion_area;
2268 Polygons total_fill_area;
2269 for (const LayerRegion *region : layer->regions()) {
2270 Polygons internal_polys = to_polygons(region->fill_surfaces().filter_by_types({stInternal, stInternalSolid}));
2271 expansion_area.insert(expansion_area.end(), internal_polys.begin(), internal_polys.end());
2272 Polygons fill_polys = to_polygons(region->fill_expolygons());
2273 total_fill_area.insert(total_fill_area.end(), fill_polys.begin(), fill_polys.end());
2274 if (region->region().config().fill_pattern == ipLightning) {
2275 Polygons l = to_polygons(region->fill_surfaces().filter_by_type(stInternal));
2276 lightning_area.insert(lightning_area.end(), l.begin(), l.end());
2277 }
2278 }
2279 total_fill_area = closing(total_fill_area, float(SCALED_EPSILON));
2280 expansion_area = closing(expansion_area, float(SCALED_EPSILON));
2281 expansion_area = intersection(expansion_area, deep_infill_area);
2282 Polylines anchors = intersection_pl(infill_lines[lidx - 1], shrink(expansion_area, spacing));
2283 Polygons internal_unsupported_area = shrink(deep_infill_area, spacing * 4.5);
2284
2285#ifdef DEBUG_BRIDGE_OVER_INFILL
2286 debug_draw(std::to_string(lidx) + "_" + std::to_string(cluster_idx) + "_" + std::to_string(job_idx) + "_" + "_total_area",
2287 to_lines(total_fill_area), to_lines(expansion_area), to_lines(deep_infill_area), to_lines(anchors));
2288#endif
2289
2290 std::vector<CandidateSurface> expanded_surfaces;
2291 expanded_surfaces.reserve(surfaces_by_layer[lidx].size());
2292 for (const CandidateSurface &candidate : surfaces_by_layer[lidx]) {
2293 const Flow &flow = candidate.region->bridging_flow(frSolidInfill, true);
2294 Polygons area_to_be_bridge = expand(candidate.new_polys, flow.scaled_spacing());
2295 area_to_be_bridge = intersection(area_to_be_bridge, deep_infill_area);
2296
2297 area_to_be_bridge.erase(std::remove_if(area_to_be_bridge.begin(), area_to_be_bridge.end(),
2298 [internal_unsupported_area](const Polygon &p) {
2299 return intersection({p}, internal_unsupported_area).empty();
2300 }),
2301 area_to_be_bridge.end());
2302
2303 Polygons limiting_area = union_(area_to_be_bridge, expansion_area);
2304
2305 if (area_to_be_bridge.empty())
2306 continue;
2307
2308 Polylines boundary_plines = to_polylines(expand(total_fill_area, 1.3 * flow.scaled_spacing()));
2309 {
2310 Polylines limiting_plines = to_polylines(expand(limiting_area, 0.3*flow.spacing()));
2311 boundary_plines.insert(boundary_plines.end(), limiting_plines.begin(), limiting_plines.end());
2312 }
2313
2314#ifdef DEBUG_BRIDGE_OVER_INFILL
2315 int r = rand();
2316 debug_draw(std::to_string(lidx) + "_" + std::to_string(cluster_idx) + "_" + std::to_string(job_idx) + "_" +
2317 "_anchors_" + std::to_string(r),
2318 to_lines(area_to_be_bridge), to_lines(boundary_plines), to_lines(anchors), to_lines(expansion_area));
2319#endif
2320
2321 double bridging_angle = 0;
2322 if (!anchors.empty()) {
2323 bridging_angle = determine_bridging_angle(area_to_be_bridge, to_lines(anchors),
2324 candidate.region->region().config().fill_pattern.value);
2325 } else {
2326 // use expansion boundaries as anchors.
2327 // Also, use Infill pattern that is neutral for angle determination, since there are no infill lines.
2328 bridging_angle = determine_bridging_angle(area_to_be_bridge, to_lines(boundary_plines), InfillPattern::ipLine);
2329 }
2330
2331 boundary_plines.insert(boundary_plines.end(), anchors.begin(), anchors.end());
2332 if (!lightning_area.empty() && !intersection(area_to_be_bridge, lightning_area).empty()) {
2333 boundary_plines = intersection_pl(boundary_plines, expand(area_to_be_bridge, scale_(10)));
2334 }
2335 Polygons bridging_area = construct_anchored_polygon(area_to_be_bridge, to_lines(boundary_plines), flow, bridging_angle);
2336
2337 // Check collision with other expanded surfaces
2338 {
2339 bool reconstruct = false;
2340 Polygons tmp_expanded_area = expand(bridging_area, 3.0 * flow.scaled_spacing());
2341 for (const CandidateSurface &s : expanded_surfaces) {
2342 if (!intersection(s.new_polys, tmp_expanded_area).empty()) {
2343 bridging_angle = s.bridge_angle;
2344 reconstruct = true;
2345 break;
2346 }
2347 }
2348 if (reconstruct) {
2349 bridging_area = construct_anchored_polygon(area_to_be_bridge, to_lines(boundary_plines), flow, bridging_angle);
2350 }
2351 }
2352
2353 bridging_area = opening(bridging_area, flow.scaled_spacing());
2354 bridging_area = closing(bridging_area, flow.scaled_spacing());
2355 bridging_area = intersection(bridging_area, limiting_area);
2356 bridging_area = intersection(bridging_area, total_fill_area);
2357 expansion_area = diff(expansion_area, bridging_area);
2358
2359#ifdef DEBUG_BRIDGE_OVER_INFILL
2360 debug_draw(std::to_string(lidx) + "_" + std::to_string(cluster_idx) + "_" + std::to_string(job_idx) + "_" + "_expanded_bridging" + std::to_string(r),
2361 to_lines(layer->lslices), to_lines(boundary_plines), to_lines(candidate.new_polys), to_lines(bridging_area));
2362#endif
2363
2364 expanded_surfaces.push_back(CandidateSurface(candidate.original_surface, candidate.layer_index, bridging_area,
2365 candidate.region, bridging_angle));
2366 }
2367 surfaces_by_layer[lidx].swap(expanded_surfaces);
2368 expanded_surfaces.clear();
2369 }
2370 }
2371 });
2372
2373 BOOST_LOG_TRIVIAL(info) << "Bridge over infill - Directions and expanded surfaces computed" << log_memory_info();
2374
2375 tbb::parallel_for(tbb::blocked_range<size_t>(0, this->layers().size()), [po = this, &surfaces_by_layer](tbb::blocked_range<size_t> r) {
2376 PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
2377 for (size_t lidx = r.begin(); lidx < r.end(); lidx++) {
2378 if (surfaces_by_layer.find(lidx) == surfaces_by_layer.end() && surfaces_by_layer.find(lidx + 1) == surfaces_by_layer.end())
2379 continue;
2380 Layer *layer = po->get_layer(lidx);
2381
2382 Polygons cut_from_infill{};
2383 if (surfaces_by_layer.find(lidx) != surfaces_by_layer.end()) {
2384 for (const auto &surface : surfaces_by_layer.at(lidx)) {
2385 cut_from_infill.insert(cut_from_infill.end(), surface.new_polys.begin(), surface.new_polys.end());
2386 }
2387 }
2388
2389 Polygons additional_ensuring_areas{};
2390 if (surfaces_by_layer.find(lidx + 1) != surfaces_by_layer.end()) {
2391 for (const auto &surface : surfaces_by_layer.at(lidx + 1)) {
2392 auto additional_area = diff(surface.new_polys,
2393 shrink(surface.new_polys, surface.region->flow(frSolidInfill).scaled_spacing()));
2394 additional_ensuring_areas.insert(additional_ensuring_areas.end(), additional_area.begin(), additional_area.end());
2395 }
2396 }
2397
2398 for (LayerRegion *region : layer->regions()) {
2399 Surfaces new_surfaces;
2400
2401 Polygons near_perimeters = to_polygons(union_safety_offset_ex(to_polygons(region->fill_surfaces().surfaces)));
2402 near_perimeters = diff(near_perimeters, shrink(near_perimeters, region->flow(frSolidInfill).scaled_spacing()));
2403 ExPolygons additional_ensuring = intersection_ex(additional_ensuring_areas, near_perimeters);
2404
2405 SurfacesPtr internal_infills = region->m_fill_surfaces.filter_by_type(stInternal);
2406 ExPolygons new_internal_infills = diff_ex(internal_infills, cut_from_infill);
2407 new_internal_infills = diff_ex(new_internal_infills, additional_ensuring);
2408 for (const ExPolygon &ep : new_internal_infills) {
2409 new_surfaces.emplace_back(stInternal, ep);
2410 }
2411
2412 SurfacesPtr internal_solids = region->m_fill_surfaces.filter_by_type(stInternalSolid);
2413 if (surfaces_by_layer.find(lidx) != surfaces_by_layer.end()) {
2414 for (const CandidateSurface &cs : surfaces_by_layer.at(lidx)) {
2415 for (const Surface *surface : internal_solids) {
2416 if (cs.original_surface == surface) {
2417 Surface tmp{*surface, {}};
2418 tmp.surface_type = stInternalBridge;
2419 tmp.bridge_angle = cs.bridge_angle;
2420 for (const ExPolygon &ep : union_ex(cs.new_polys)) {
2421 new_surfaces.emplace_back(tmp, ep);
2422 }
2423 break;
2424 }
2425 }
2426 }
2427 }
2428 ExPolygons new_internal_solids = to_expolygons(internal_solids);
2429 new_internal_solids.insert(new_internal_solids.end(), additional_ensuring.begin(), additional_ensuring.end());
2430 new_internal_solids = diff_ex(new_internal_solids, cut_from_infill);
2431 new_internal_solids = union_safety_offset_ex(new_internal_solids);
2432 for (const ExPolygon &ep : new_internal_solids) {
2433 new_surfaces.emplace_back(stInternalSolid, ep);
2434 }
2435
2436#ifdef DEBUG_BRIDGE_OVER_INFILL
2437 debug_draw("Aensuring_" + std::to_string(reinterpret_cast<uint64_t>(&region)), to_polylines(additional_ensuring),
2438 to_polylines(near_perimeters), to_polylines(to_polygons(internal_infills)),
2439 to_polylines(to_polygons(internal_solids)));
2440 debug_draw("Aensuring_" + std::to_string(reinterpret_cast<uint64_t>(&region)) + "_new", to_polylines(additional_ensuring),
2441 to_polylines(near_perimeters), to_polylines(to_polygons(new_internal_infills)),
2442 to_polylines(to_polygons(new_internal_solids)));
2443#endif
2444
2445 region->m_fill_surfaces.remove_types({stInternalSolid, stInternal});
2446 region->m_fill_surfaces.append(new_surfaces);
2447 }
2448 }
2449 });
2450
2451 BOOST_LOG_TRIVIAL(info) << "Bridge over infill - End" << log_memory_info();
2452
2453} // void PrintObject::bridge_over_infill()
EIGEN_DEVICE_FUNC const CosReturnType cos() const
Definition ArrayCwiseUnaryOps.h:202
EIGEN_DEVICE_FUNC const SinReturnType sin() const
Definition ArrayCwiseUnaryOps.h:220
EIGEN_DEVICE_FUNC const RoundReturnType round() const
Definition ArrayCwiseUnaryOps.h:374
EIGEN_DEVICE_FUNC SegmentReturnType segment(Index start, Index n)
This is the const version of segment(Index,Index).
Definition BlockMethods.h:888
#define PRINT_OBJECT_TIME_LIMIT_MILLIS(limit)
Definition PrintObject.cpp:73
ExPolygons lslices
Definition Layer.hpp:339
Points points
Definition MultiPoint.hpp:18
size_t num_printing_regions() const
Definition Print.hpp:312
auto layers() const
Definition Print.hpp:247
PrintObject(Print *print, ModelObject *model_object, const Transform3d &trafo, PrintInstances &&instances)
Definition PrintObject.cpp:97
const PrintRegion & printing_region(size_t idx) const
Definition Print.hpp:313
FillLightning::GeneratorPtr m_lightning_generator
Definition Print.hpp:418
std::pair< FillAdaptive::OctreePtr, FillAdaptive::OctreePtr > m_adaptive_fill_octrees
Definition Print.hpp:417
const Vec3crd & size() const
Definition Print.hpp:245
size_t layer_count() const
Definition Print.hpp:278
const Layer * get_layer(int idx) const
Definition Print.hpp:280
FillLightning::GeneratorPtr prepare_lightning_infill_data()
Definition PrintObject.cpp:574
std::pair< FillAdaptive::OctreePtr, FillAdaptive::OctreePtr > prepare_adaptive_infill_data(const std::vector< std::pair< const Surface *, float > > &surfaces_w_bottom_z) const
Definition PrintObject.cpp:536
const PrintRegionConfig & config() const
Definition Print.hpp:87
static constexpr double PI
Definition libslic3r.h:58
#define SCALED_EPSILON
Definition libslic3r.h:71
#define scale_(val)
Definition libslic3r.h:69
ClusteredPoints cluster(Index3D &sindex, unsigned max_points, std::function< std::vector< PointIndexEl >(const Index3D &, const PointIndexEl &)> qfn)
Definition Clustering.cpp:19
std::vector< Polygon, PointsAllocator< Polygon > > Polygons
Definition Polygon.hpp:15
InfillPattern
Definition PrintConfig.hpp:60
@ ipHilbertCurve
Definition PrintConfig.hpp:62
@ ipOctagramSpiral
Definition PrintConfig.hpp:62
@ ipLightning
Definition PrintConfig.hpp:63
std::vector< Line > Lines
Definition Line.hpp:17
BoundingBox scaled(const BoundingBoxf &bb)
Definition BoundingBox.hpp:240
std::vector< const Surface * > SurfacesPtr
Definition Surface.hpp:98
Polylines to_polylines(const ExPolygon &src)
Definition ExPolygon.hpp:209
bridge_angle((ConfigOptionInt, bottom_solid_layers))((ConfigOptionFloat
Slic3r::ExPolygons diff_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset)
Definition ClipperUtils.cpp:726
Slic3r::Polygons expand(const Slic3r::Polygon &polygon, const float delta, ClipperLib::JoinType joinType=DefaultJoinType, double miterLimit=DefaultMiterLimit)
Definition ClipperUtils.hpp:363
Slic3r::ExPolygons union_ex(const Slic3r::Polygons &subject, ClipperLib::PolyFillType fill_type)
Definition ClipperUtils.cpp:774
Eigen::Matrix< double, 2, 1, Eigen::DontAlign > Vec2d
Definition Point.hpp:51
@ frSolidInfill
Definition Flow.hpp:20
std::vector< ExPolygon > ExPolygons
Definition ExPolygon.hpp:13
Slic3r::Polygons shrink(const Slic3r::Polygons &polygons, const float delta, ClipperLib::JoinType joinType=DefaultJoinType, double miterLimit=DefaultMiterLimit)
Definition ClipperUtils.hpp:372
Slic3r::Polygons intersection(const Slic3r::Polygon &subject, const Slic3r::Polygon &clip, ApplySafetyOffset do_safety_offset)
Definition ClipperUtils.cpp:686
double area(const ExPolygon &poly)
Definition ExPolygon.hpp:467
Lines to_lines(const ExPolygon &src)
Definition ExPolygon.hpp:117
ExPolygons to_expolygons(const Polygons &polys)
Definition ExPolygon.hpp:347
Slic3r::ExPolygons closing_ex(const Slic3r::Polygons &polygons, const float delta1, const float delta2, ClipperLib::JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:593
BoundingBox get_extents(const ExPolygon &expolygon)
Definition ExPolygon.cpp:352
double angle(const Eigen::MatrixBase< Derived > &v1, const Eigen::MatrixBase< Derived2 > &v2)
Definition Point.hpp:112
std::string log_memory_info(bool ignore_loglevel)
Definition utils.cpp:1073
Slic3r::Polygons closing(const Slic3r::Polygons &polygons, const float delta1, const float delta2, ClipperLib::JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:587
Polygons to_polygons(const ExPolygon &src)
Definition ExPolygon.hpp:281
std::vector< Surface > Surfaces
Definition Surface.hpp:97
Slic3r::ExPolygons intersection_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset)
Definition ClipperUtils.cpp:755
Slic3r::ExPolygons union_safety_offset_ex(const Slic3r::Polygons &polygons)
Definition ClipperUtils.hpp:354
Slic3r::Polygons union_safety_offset(const Slic3r::Polygons &polygons)
Definition ClipperUtils.hpp:352
@ stInternalSolid
Definition Surface.hpp:19
@ stInternal
Definition Surface.hpp:17
@ stInternalBridge
Definition Surface.hpp:21
@ stInternalVoid
Definition Surface.hpp:24
void polygons_rotate(Polygons &polys, double angle)
Definition Polygon.hpp:155
Slic3r::Polygons diff(const Slic3r::Polygon &subject, const Slic3r::Polygon &clip, ApplySafetyOffset do_safety_offset)
Definition ClipperUtils.cpp:672
std::vector< Point, PointsAllocator< Point > > Points
Definition Point.hpp:58
IGL_INLINE void find(const Eigen::SparseMatrix< T > &X, Eigen::DenseBase< DerivedI > &I, Eigen::DenseBase< DerivedJ > &J, Eigen::DenseBase< DerivedV > &V)
Definition find.cpp:18
TCoord< P > x(const P &p)
Definition geometry_traits.hpp:297
double distance(const P &p1, const P &p2)
Definition geometry_traits.hpp:329
S::iterator begin(S &sh, const PathTag &)
Definition geometry_traits.hpp:614
S::iterator end(S &sh, const PathTag &)
Definition geometry_traits.hpp:620
Slic3r::Polygon Polygon
Definition Emboss.cpp:34
unsigned __int64 uint64_t
Definition unistd.h:80

References Slic3r::bridge_angle(), Slic3r::closing(), Slic3r::diff(), Slic3r::diff_ex(), EPSILON, Slic3r::expand(), Slic3r::frSolidInfill, Slic3r::intersection(), Slic3r::intersection_ex(), Slic3r::ipLightning, Slic3r::log_memory_info(), Slic3r::Layer::lower_layer, PRINT_OBJECT_TIME_LIMIT_MILLIS, Slic3r::Layer::regions(), scale_, SCALED_EPSILON, Slic3r::shrink(), Slic3r::stInternal, Slic3r::stInternalSolid, Slic3r::to_expolygons(), Slic3r::to_lines(), Slic3r::to_polygons(), and Slic3r::union_safety_offset_ex().

+ Here is the call graph for this function:

◆ cancel_callback()

std::function< void()> Slic3r::PrintObjectBase::cancel_callback ( PrintBase print)
staticprotectedinherited
116{
117 return print->cancel_callback();
118}

References Slic3r::PrintBase::cancel_callback().

Referenced by Slic3r::PrintObjectBaseWithState< PrintType, PrintObjectStepEnumType, COUNT >::invalidate_all_steps(), Slic3r::PrintObjectBaseWithState< PrintType, PrintObjectStepEnumType, COUNT >::invalidate_step(), Slic3r::PrintObjectBaseWithState< PrintType, PrintObjectStepEnumType, COUNT >::invalidate_steps(), and Slic3r::PrintObjectBaseWithState< PrintType, PrintObjectStepEnumType, COUNT >::invalidate_steps().

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

◆ center_offset()

const Point & Slic3r::PrintObject::center_offset ( ) const
inline
266{ return m_center_offset; }

References m_center_offset.

◆ cleanup()

void Slic3r::PrintObject::cleanup ( )
private
887{
889 this->clear_fills();
891 this->clear_support_layers();
892}
bool query_reset_dirty_step_unguarded(PrintObjectStepEnum step)
Definition PrintBase.hpp:790
void clear_fills()
Definition PrintObject.cpp:409
@ posInfill
Definition Print.hpp:70
@ posSupportMaterial
Definition Print.hpp:70

References Slic3r::posInfill, and Slic3r::posSupportMaterial.

◆ clear_fills()

void Slic3r::PrintObject::clear_fills ( )
private
410{
411 for (Layer *layer : m_layers)
412 layer->clear_fills();
413}

◆ clear_layers()

void Slic3r::PrintObject::clear_layers ( )
593{
594 for (Layer *l : m_layers)
595 delete l;
596 m_layers.clear();
597}

Referenced by ~PrintObject().

+ Here is the caller graph for this function:

◆ clear_support_layers()

void Slic3r::PrintObject::clear_support_layers ( )
606{
607 for (Layer *l : m_support_layers)
608 delete l;
609 m_support_layers.clear();
610}

Referenced by ~PrintObject().

+ Here is the caller graph for this function:

◆ clip_fill_surfaces()

void Slic3r::PrintObject::clip_fill_surfaces ( )
private

◆ combine_infill()

void Slic3r::PrintObject::combine_infill ( )
private
2761{
2762 // Work on each region separately.
2763 for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id) {
2764 const PrintRegion &region = this->printing_region(region_id);
2765 const size_t every = region.config().infill_every_layers.value;
2766 if (every < 2 || region.config().fill_density == 0.)
2767 continue;
2768 // Limit the number of combined layers to the maximum height allowed by this regions' nozzle.
2769 //FIXME limit the layer height to max_layer_height
2770 double nozzle_diameter = std::min(
2771 this->print()->config().nozzle_diameter.get_at(region.config().infill_extruder.value - 1),
2772 this->print()->config().nozzle_diameter.get_at(region.config().solid_infill_extruder.value - 1));
2773 // define the combinations
2774 std::vector<size_t> combine(m_layers.size(), 0);
2775 {
2776 double current_height = 0.;
2777 size_t num_layers = 0;
2778 for (size_t layer_idx = 0; layer_idx < m_layers.size(); ++ layer_idx) {
2780 const Layer *layer = m_layers[layer_idx];
2781 if (layer->id() == 0)
2782 // Skip first print layer (which may not be first layer in array because of raft).
2783 continue;
2784 // Check whether the combination of this layer with the lower layers' buffer
2785 // would exceed max layer height or max combined layer count.
2786 if (current_height + layer->height >= nozzle_diameter + EPSILON || num_layers >= every) {
2787 // Append combination to lower layer.
2788 combine[layer_idx - 1] = num_layers;
2789 current_height = 0.;
2790 num_layers = 0;
2791 }
2792 current_height += layer->height;
2793 ++ num_layers;
2794 }
2795
2796 // Append lower layers (if any) to uppermost layer.
2797 combine[m_layers.size() - 1] = num_layers;
2798 }
2799
2800 // loop through layers to which we have assigned layers to combine
2801 for (size_t layer_idx = 0; layer_idx < m_layers.size(); ++ layer_idx) {
2803 size_t num_layers = combine[layer_idx];
2804 if (num_layers <= 1)
2805 continue;
2806 // Get all the LayerRegion objects to be combined.
2807 std::vector<LayerRegion*> layerms;
2808 layerms.reserve(num_layers);
2809 for (size_t i = layer_idx + 1 - num_layers; i <= layer_idx; ++ i)
2810 layerms.emplace_back(m_layers[i]->regions()[region_id]);
2811 // We need to perform a multi-layer intersection, so let's split it in pairs.
2812 // Initialize the intersection with the candidates of the lowest layer.
2813 ExPolygons intersection = to_expolygons(layerms.front()->fill_surfaces().filter_by_type(stInternal));
2814 // Start looping from the second layer and intersect the current intersection with it.
2815 for (size_t i = 1; i < layerms.size(); ++ i)
2816 intersection = intersection_ex(layerms[i]->fill_surfaces().filter_by_type(stInternal), intersection);
2817 double area_threshold = layerms.front()->infill_area_threshold();
2818 if (! intersection.empty() && area_threshold > 0.)
2819 intersection.erase(std::remove_if(intersection.begin(), intersection.end(),
2820 [area_threshold](const ExPolygon &expoly) { return expoly.area() <= area_threshold; }),
2821 intersection.end());
2822 if (intersection.empty())
2823 continue;
2824// Slic3r::debugf " combining %d %s regions from layers %d-%d\n",
2825// scalar(@$intersection),
2826// ($type == stInternal ? 'internal' : 'internal-solid'),
2827// $layer_idx-($every-1), $layer_idx;
2828 // intersection now contains the regions that can be combined across the full amount of layers,
2829 // so let's remove those areas from all layers.
2830 Polygons intersection_with_clearance;
2831 intersection_with_clearance.reserve(intersection.size());
2832 float clearance_offset =
2833 0.5f * layerms.back()->flow(frPerimeter).scaled_width() +
2834 // Because fill areas for rectilinear and honeycomb are grown
2835 // later to overlap perimeters, we need to counteract that too.
2836 ((region.config().fill_pattern == ipRectilinear ||
2837 region.config().fill_pattern == ipMonotonic ||
2838 region.config().fill_pattern == ipGrid ||
2839 region.config().fill_pattern == ipLine ||
2840 region.config().fill_pattern == ipHoneycomb) ? 1.5f : 0.5f) *
2841 layerms.back()->flow(frSolidInfill).scaled_width();
2842 for (ExPolygon &expoly : intersection)
2843 polygons_append(intersection_with_clearance, offset(expoly, clearance_offset));
2844 for (LayerRegion *layerm : layerms) {
2845 Polygons internal = to_polygons(std::move(layerm->fill_surfaces().filter_by_type(stInternal)));
2846 layerm->m_fill_surfaces.remove_type(stInternal);
2847 layerm->m_fill_surfaces.append(diff_ex(internal, intersection_with_clearance), stInternal);
2848 if (layerm == layerms.back()) {
2849 // Apply surfaces back with adjusted depth to the uppermost layer.
2850 Surface templ(stInternal, ExPolygon());
2851 templ.thickness = 0.;
2852 for (LayerRegion *layerm2 : layerms)
2853 templ.thickness += layerm2->layer()->height;
2854 templ.thickness_layers = (unsigned short)layerms.size();
2855 layerm->m_fill_surfaces.append(intersection, templ);
2856 } else {
2857 // Save void surfaces.
2858 layerm->m_fill_surfaces.append(
2859 intersection_ex(internal, intersection_with_clearance),
2861 }
2862 }
2863 }
2864 }
2865} // void PrintObject::combine_infill()
void throw_if_canceled() const
Definition PrintBase.hpp:544
const PrintObjectConfig & config() const
Definition Print.hpp:246
@ ipGrid
Definition PrintConfig.hpp:61
@ ipMonotonic
Definition PrintConfig.hpp:61
@ ipLine
Definition PrintConfig.hpp:61
@ ipHoneycomb
Definition PrintConfig.hpp:61
@ ipRectilinear
Definition PrintConfig.hpp:61
@ frPerimeter
Definition Flow.hpp:18
Slic3r::Polygons offset(const Slic3r::Polygon &polygon, const float delta, ClipperLib::JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:416
void polygons_append(Polygons &dst, const ExPolygon &src)
Definition ExPolygon.hpp:375
IGL_INLINE void combine(const std::vector< DerivedVV > &VV, const std::vector< DerivedFF > &FF, Eigen::PlainObjectBase< DerivedV > &V, Eigen::PlainObjectBase< DerivedF > &F, Eigen::PlainObjectBase< DerivedVsizes > &Vsizes, Eigen::PlainObjectBase< DerivedFsizes > &Fsizes)
Definition combine.cpp:18
Definition Eigen_Colamd.h:50
TPoint< P > back(const P &p)
Definition geometry_traits.hpp:873

References Slic3r::PrintRegion::config(), Slic3r::diff_ex(), EPSILON, Slic3r::frPerimeter, Slic3r::frSolidInfill, Slic3r::Layer::height, Slic3r::Layer::id(), Slic3r::intersection(), Slic3r::intersection_ex(), Slic3r::ipGrid, Slic3r::ipHoneycomb, Slic3r::ipLine, Slic3r::ipMonotonic, Slic3r::ipRectilinear, Slic3r::polygons_append(), Slic3r::stInternal, Slic3r::stInternalVoid, Slic3r::Surface::thickness, Slic3r::Surface::thickness_layers, Slic3r::to_expolygons(), and Slic3r::to_polygons().

+ Here is the call graph for this function:

◆ config()

◆ config_apply()

void Slic3r::PrintObject::config_apply ( const ConfigBase other,
bool  ignore_nonexistent = false 
)
inlineprivate
351{ m_config.apply(other, ignore_nonexistent); }

References m_config.

Referenced by Slic3r::Print::apply().

+ Here is the caller graph for this function:

◆ config_apply_only()

void Slic3r::PrintObject::config_apply_only ( const ConfigBase other,
const t_config_option_keys keys,
bool  ignore_nonexistent = false 
)
inlineprivate
352{ m_config.apply_only(other, keys, ignore_nonexistent); }

References m_config.

◆ copy_id()

void Slic3r::ObjectBase::copy_id ( const ObjectBase rhs)
inlineprotectedinherited
76{ m_id = rhs.id(); }
ObjectID m_id
Definition ObjectID.hpp:82
size_t id
Definition ObjectID.hpp:37

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

Referenced by Slic3r::CutObjectBase::copy().

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

◆ delete_support_layer()

void Slic3r::PrintObject::delete_support_layer ( int  idx)

◆ detect_surfaces_type()

void Slic3r::PrintObject::detect_surfaces_type ( )
private
904{
905 BOOST_LOG_TRIVIAL(info) << "Detecting solid surfaces..." << log_memory_info();
906
907 // Interface shells: the intersecting parts are treated as self standing objects supporting each other.
908 // Each of the objects will have a full number of top / bottom layers, even if these top / bottom layers
909 // are completely hidden inside a collective body of intersecting parts.
910 // This is useful if one of the parts is to be dissolved, or if it is transparent and the internal shells
911 // should be visible.
912 bool spiral_vase = this->print()->config().spiral_vase.value;
913 bool interface_shells = ! spiral_vase && m_config.interface_shells.value;
914 size_t num_layers = spiral_vase ? std::min(size_t(this->printing_region(0).config().bottom_solid_layers), m_layers.size()) : m_layers.size();
915
916 for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id) {
917 BOOST_LOG_TRIVIAL(debug) << "Detecting solid surfaces for region " << region_id << " in parallel - start";
918#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
919 for (Layer *layer : m_layers)
920 layer->m_regions[region_id]->export_region_fill_surfaces_to_svg_debug("1_detect_surfaces_type-initial");
921#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
922
923 // If interface shells are allowed, the region->surfaces cannot be overwritten as they may be used by other threads.
924 // Cache the result of the following parallel_loop.
925 std::vector<Surfaces> surfaces_new;
926 if (interface_shells)
927 surfaces_new.assign(num_layers, Surfaces());
928
929 tbb::parallel_for(
930 tbb::blocked_range<size_t>(0,
931 spiral_vase ?
932 // In spiral vase mode, reserve the last layer for the top surface if more than 1 layer is planned for the vase bottom.
933 ((num_layers > 1) ? num_layers - 1 : num_layers) :
934 // In non-spiral vase mode, go over all layers.
935 m_layers.size()),
936 [this, region_id, interface_shells, &surfaces_new](const tbb::blocked_range<size_t>& range) {
937 PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
938 // If we have soluble support material, don't bridge. The overhang will be squished against a soluble layer separating
939 // the support from the print.
940 SurfaceType surface_type_bottom_other =
941 (this->has_support() && m_config.support_material_contact_distance.value == 0) ?
942 stBottom : stBottomBridge;
943 for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) {
944 m_print->throw_if_canceled();
945 // BOOST_LOG_TRIVIAL(trace) << "Detecting solid surfaces for region " << region_id << " and layer " << layer->print_z;
946 Layer *layer = m_layers[idx_layer];
947 LayerRegion *layerm = layer->m_regions[region_id];
948 // comparison happens against the *full* slices (considering all regions)
949 // unless internal shells are requested
950 Layer *upper_layer = (idx_layer + 1 < this->layer_count()) ? m_layers[idx_layer + 1] : nullptr;
951 Layer *lower_layer = (idx_layer > 0) ? m_layers[idx_layer - 1] : nullptr;
952 // collapse very narrow parts (using the safety offset in the diff is not enough)
953 float offset = layerm->flow(frExternalPerimeter).scaled_width() / 10.f;
954
955 // find top surfaces (difference between current surfaces
956 // of current layer and upper one)
957 Surfaces top;
958 if (upper_layer) {
959 ExPolygons upper_slices = interface_shells ?
960 diff_ex(layerm->slices().surfaces, upper_layer->m_regions[region_id]->slices().surfaces, ApplySafetyOffset::Yes) :
961 diff_ex(layerm->slices().surfaces, upper_layer->lslices, ApplySafetyOffset::Yes);
962 surfaces_append(top, opening_ex(upper_slices, offset), stTop);
963 } else {
964 // if no upper layer, all surfaces of this one are solid
965 // we clone surfaces because we're going to clear the slices collection
966 top = layerm->slices().surfaces;
967 for (Surface &surface : top)
968 surface.surface_type = stTop;
969 }
970
971 // Find bottom surfaces (difference between current surfaces of current layer and lower one).
972 Surfaces bottom;
973 if (lower_layer) {
974#if 0
975 //FIXME Why is this branch failing t\multi.t ?
976 Polygons lower_slices = interface_shells ?
977 to_polygons(lower_layer->get_region(region_id)->slices.surfaces) :
978 to_polygons(lower_layer->slices);
979 surfaces_append(bottom,
980 opening_ex(diff(layerm->slices.surfaces, lower_slices, true), offset),
981 surface_type_bottom_other);
982#else
983 // Any surface lying on the void is a true bottom bridge (an overhang)
985 bottom,
987 diff_ex(layerm->slices().surfaces, lower_layer->lslices, ApplySafetyOffset::Yes),
988 offset),
989 surface_type_bottom_other);
990 // if user requested internal shells, we need to identify surfaces
991 // lying on other slices not belonging to this region
992 if (interface_shells) {
993 // non-bridging bottom surfaces: any part of this layer lying
994 // on something else, excluding those lying on our own region
996 bottom,
998 diff_ex(
999 intersection(layerm->slices().surfaces, lower_layer->lslices), // supported
1000 lower_layer->m_regions[region_id]->slices().surfaces,
1001 ApplySafetyOffset::Yes),
1002 offset),
1003 stBottom);
1004 }
1005#endif
1006 } else {
1007 // if no lower layer, all surfaces of this one are solid
1008 // we clone surfaces because we're going to clear the slices collection
1009 bottom = layerm->slices().surfaces;
1010 for (Surface &surface : bottom)
1011 surface.surface_type = stBottom;
1012 }
1013
1014 // now, if the object contained a thin membrane, we could have overlapping bottom
1015 // and top surfaces; let's do an intersection to discover them and consider them
1016 // as bottom surfaces (to allow for bridge detection)
1017 if (! top.empty() && ! bottom.empty()) {
1018 // Polygons overlapping = intersection(to_polygons(top), to_polygons(bottom));
1019 // Slic3r::debugf " layer %d contains %d membrane(s)\n", $layerm->layer->id, scalar(@$overlapping)
1020 // if $Slic3r::debug;
1021 Polygons top_polygons = to_polygons(std::move(top));
1022 top.clear();
1023 surfaces_append(top, diff_ex(top_polygons, bottom), stTop);
1024 }
1025
1026 #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
1027 {
1028 static int iRun = 0;
1029 std::vector<std::pair<Slic3r::ExPolygons, SVG::ExPolygonAttributes>> expolygons_with_attributes;
1030 expolygons_with_attributes.emplace_back(std::make_pair(union_ex(top), SVG::ExPolygonAttributes("green")));
1031 expolygons_with_attributes.emplace_back(std::make_pair(union_ex(bottom), SVG::ExPolygonAttributes("brown")));
1032 expolygons_with_attributes.emplace_back(std::make_pair(to_expolygons(layerm->slices().surfaces), SVG::ExPolygonAttributes("black")));
1033 SVG::export_expolygons(debug_out_path("1_detect_surfaces_type_%d_region%d-layer_%f.svg", iRun ++, region_id, layer->print_z).c_str(), expolygons_with_attributes);
1034 }
1035 #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
1036
1037 // save surfaces to layer
1038 Surfaces &surfaces_out = interface_shells ? surfaces_new[idx_layer] : layerm->m_slices.surfaces;
1039 Surfaces surfaces_backup;
1040 if (! interface_shells) {
1041 surfaces_backup = std::move(surfaces_out);
1042 surfaces_out.clear();
1043 }
1044 const Surfaces &surfaces_prev = interface_shells ? layerm->slices().surfaces : surfaces_backup;
1045
1046 // find internal surfaces (difference between top/bottom surfaces and others)
1047 {
1048 Polygons topbottom = to_polygons(top);
1049 polygons_append(topbottom, to_polygons(bottom));
1050 surfaces_append(surfaces_out, diff_ex(surfaces_prev, topbottom), stInternal);
1051 }
1052
1053 surfaces_append(surfaces_out, std::move(top));
1054 surfaces_append(surfaces_out, std::move(bottom));
1055
1056 // Slic3r::debugf " layer %d has %d bottom, %d top and %d internal surfaces\n",
1057 // $layerm->layer->id, scalar(@bottom), scalar(@top), scalar(@internal) if $Slic3r::debug;
1058
1059 #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
1060 layerm->export_region_slices_to_svg_debug("detect_surfaces_type-final");
1061 #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
1062 }
1063 }
1064 ); // for each layer of a region
1065 m_print->throw_if_canceled();
1066
1067 if (interface_shells) {
1068 // Move surfaces_new to layerm->slices.surfaces
1069 for (size_t idx_layer = 0; idx_layer < num_layers; ++ idx_layer)
1070 m_layers[idx_layer]->m_regions[region_id]->m_slices.set(std::move(surfaces_new[idx_layer]));
1071 }
1072
1073 if (spiral_vase) {
1074 if (num_layers > 1)
1075 // Turn the last bottom layer infill to a top infill, so it will be extruded with a proper pattern.
1076 m_layers[num_layers - 1]->m_regions[region_id]->m_slices.set_type(stTop);
1077 for (size_t i = num_layers; i < m_layers.size(); ++ i)
1078 m_layers[i]->m_regions[region_id]->m_slices.set_type(stInternal);
1079 }
1080
1081 BOOST_LOG_TRIVIAL(debug) << "Detecting solid surfaces for region " << region_id << " - clipping in parallel - start";
1082 // Fill in layerm->fill_surfaces by trimming the layerm->slices by the cummulative layerm->fill_surfaces.
1083 tbb::parallel_for(
1084 tbb::blocked_range<size_t>(0, m_layers.size()),
1085 [this, region_id](const tbb::blocked_range<size_t>& range) {
1086 PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
1087 for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) {
1088 m_print->throw_if_canceled();
1089 LayerRegion *layerm = m_layers[idx_layer]->m_regions[region_id];
1090 layerm->slices_to_fill_surfaces_clipped();
1091#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
1092 layerm->export_region_fill_surfaces_to_svg_debug("1_detect_surfaces_type-final");
1093#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
1094 } // for each layer of a region
1095 });
1096 m_print->throw_if_canceled();
1097 BOOST_LOG_TRIVIAL(debug) << "Detecting solid surfaces for region " << region_id << " - clipping in parallel - end";
1098 } // for each this->print->region_count
1099
1100 // Mark the object to have the region slices classified (typed, which also means they are split based on whether they are supported, bridging, top layers etc.)
1101 m_typed_slices = true;
1102}
const PrintConfig & config() const
Definition Print.hpp:597
#define const
Definition getopt.c:38
std::string debug_out_path(const char *name,...)
Definition utils.cpp:218
auto range(Cont &&cont)
Definition libslic3r.h:356
Slic3r::ExPolygons opening_ex(const Slic3r::ExPolygons &polygons, const float delta, ClipperLib::JoinType joinType=DefaultJoinType, double miterLimit=DefaultMiterLimit)
Definition ClipperUtils.hpp:408
void surfaces_append(Surfaces &dst, const ExPolygons &src, SurfaceType surfaceType)
Definition Surface.hpp:228
ApplySafetyOffset
Definition ClipperUtils.hpp:45
SurfaceType
Definition Surface.hpp:9
@ stTop
Definition Surface.hpp:11
@ stBottomBridge
Definition Surface.hpp:15
@ stBottom
Definition Surface.hpp:13
void offset(Slic3r::ExPolygon &sh, coord_t distance, const PolygonTag &)
Definition geometries.hpp:132

References Slic3r::debug_out_path(), Slic3r::diff(), Slic3r::diff_ex(), Slic3r::LayerRegion::export_region_slices_to_svg_debug(), Slic3r::LayerRegion::flow(), Slic3r::frExternalPerimeter, Slic3r::Layer::get_region(), Slic3r::intersection(), Slic3r::log_memory_info(), Slic3r::Layer::lslices, Slic3r::Layer::m_regions, Slic3r::LayerRegion::m_slices, Slic3r::opening_ex(), Slic3r::polygons_append(), PRINT_OBJECT_TIME_LIMIT_MILLIS, Slic3r::Layer::print_z, Slic3r::range(), Slic3r::Flow::scaled_width(), Slic3r::LayerRegion::slices(), Slic3r::stBottom, Slic3r::stBottomBridge, Slic3r::stInternal, Slic3r::stTop, Slic3r::SurfaceCollection::surfaces, Slic3r::surfaces_append(), Slic3r::to_expolygons(), Slic3r::to_polygons(), and Slic3r::union_ex().

+ Here is the call graph for this function:

◆ discover_horizontal_shells()

void Slic3r::PrintObject::discover_horizontal_shells ( )
private
2724{
2725 BOOST_LOG_TRIVIAL(trace) << "discover_horizontal_shells()";
2726
2727 for (size_t region_id = 0; region_id < this->num_printing_regions(); ++region_id) {
2728 for (size_t i = 0; i < m_layers.size(); ++i) {
2730 Layer *layer = m_layers[i];
2731 LayerRegion *layerm = layer->regions()[region_id];
2732 const PrintRegionConfig &region_config = layerm->region().config();
2733 if (region_config.solid_infill_every_layers.value > 0 && region_config.fill_density.value > 0 &&
2734 (i % region_config.solid_infill_every_layers) == 0) {
2735 // Insert a solid internal layer. Mark stInternal surfaces as stInternalSolid or stInternalBridge.
2736 SurfaceType type = (region_config.fill_density == 100 || region_config.solid_infill_every_layers == 1) ? stInternalSolid :
2738 for (Surface &surface : layerm->m_fill_surfaces.surfaces)
2739 if (surface.surface_type == stInternal)
2740 surface.surface_type = type;
2741 }
2742 // The rest has already been performed by discover_vertical_shells().
2743 } // for each layer
2744 } // for each region
2745
2746#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
2747 for (size_t region_id = 0; region_id < this->num_printing_regions(); ++region_id) {
2748 for (const Layer *layer : m_layers) {
2749 const LayerRegion *layerm = layer->m_regions[region_id];
2750 layerm->export_region_slices_to_svg_debug("5_discover_horizontal_shells");
2751 layerm->export_region_fill_surfaces_to_svg_debug("5_discover_horizontal_shells");
2752 } // for each layer
2753 } // for each region
2754#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
2755} // void PrintObject::discover_horizontal_shells()
if(!(yy_init))
Definition lexer.c:1190
PrintRegionConfig
Definition PrintConfig.hpp:840

References Slic3r::PrintRegion::config(), Slic3r::LayerRegion::export_region_fill_surfaces_to_svg_debug(), Slic3r::LayerRegion::export_region_slices_to_svg_debug(), Slic3r::LayerRegion::m_fill_surfaces, Slic3r::PrintRegionConfig, Slic3r::LayerRegion::region(), Slic3r::Layer::regions(), Slic3r::stInternal, Slic3r::stInternalBridge, Slic3r::stInternalSolid, and Slic3r::SurfaceCollection::surfaces.

+ Here is the call graph for this function:

◆ discover_vertical_shells()

void Slic3r::PrintObject::discover_vertical_shells ( )
private
1198{
1199 BOOST_LOG_TRIVIAL(info) << "Discovering vertical shells..." << log_memory_info();
1200
1201 struct DiscoverVerticalShellsCacheEntry
1202 {
1203 // Collected polygons, offsetted
1204 Polygons top_surfaces;
1205 Polygons bottom_surfaces;
1207 };
1208 bool spiral_vase = this->print()->config().spiral_vase.value;
1209 size_t num_layers = spiral_vase ? std::min(size_t(this->printing_region(0).config().bottom_solid_layers), m_layers.size()) : m_layers.size();
1210 std::vector<DiscoverVerticalShellsCacheEntry> cache_top_botom_regions(num_layers, DiscoverVerticalShellsCacheEntry());
1211 bool top_bottom_surfaces_all_regions = this->num_printing_regions() > 1 && ! m_config.interface_shells.value;
1212// static constexpr const float top_bottom_expansion_coeff = 1.05f;
1213 // Just a tiny fraction of an infill extrusion width to merge neighbor regions reliably.
1214 static constexpr const float top_bottom_expansion_coeff = 0.05f;
1215 if (top_bottom_surfaces_all_regions) {
1216 // This is a multi-material print and interface_shells are disabled, meaning that the vertical shell thickness
1217 // is calculated over all materials.
1218 BOOST_LOG_TRIVIAL(debug) << "Discovering vertical shells in parallel - start : cache top / bottom";
1219 //FIXME Improve the heuristics for a grain size.
1220 size_t grain_size = std::max(num_layers / 16, size_t(1));
1221 tbb::parallel_for(
1222 tbb::blocked_range<size_t>(0, num_layers, grain_size),
1223 [this, &cache_top_botom_regions](const tbb::blocked_range<size_t>& range) {
1224 PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
1225 const std::initializer_list<SurfaceType> surfaces_bottom { stBottom, stBottomBridge };
1226 const size_t num_regions = this->num_printing_regions();
1227 for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) {
1229 const Layer &layer = *m_layers[idx_layer];
1230 DiscoverVerticalShellsCacheEntry &cache = cache_top_botom_regions[idx_layer];
1231 // Simulate single set of perimeters over all merged regions.
1232 float perimeter_offset = 0.f;
1233 float perimeter_min_spacing = FLT_MAX;
1234#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
1235 static size_t debug_idx = 0;
1236 ++ debug_idx;
1237#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
1238 for (size_t region_id = 0; region_id < num_regions; ++ region_id) {
1239 LayerRegion &layerm = *layer.m_regions[region_id];
1240 float top_bottom_expansion = float(layerm.flow(frSolidInfill).scaled_spacing()) * top_bottom_expansion_coeff;
1241 // Top surfaces.
1242 append(cache.top_surfaces, offset(layerm.slices().filter_by_type(stTop), top_bottom_expansion));
1243// append(cache.top_surfaces, offset(layerm.fill_surfaces().filter_by_type(stTop), top_bottom_expansion));
1244 // Bottom surfaces.
1245 append(cache.bottom_surfaces, offset(layerm.slices().filter_by_types(surfaces_bottom), top_bottom_expansion));
1246// append(cache.bottom_surfaces, offset(layerm.fill_surfaces().filter_by_types(surfaces_bottom), top_bottom_expansion));
1247 // Calculate the maximum perimeter offset as if the slice was extruded with a single extruder only.
1248 // First find the maxium number of perimeters per region slice.
1249 unsigned int perimeters = 0;
1250 for (const Surface &s : layerm.slices())
1251 perimeters = std::max<unsigned int>(perimeters, s.extra_perimeters);
1252 perimeters += layerm.region().config().perimeters.value;
1253 // Then calculate the infill offset.
1254 if (perimeters > 0) {
1255 Flow extflow = layerm.flow(frExternalPerimeter);
1256 Flow flow = layerm.flow(frPerimeter);
1257 perimeter_offset = std::max(perimeter_offset,
1258 0.5f * float(extflow.scaled_width() + extflow.scaled_spacing()) + (float(perimeters) - 1.f) * flow.scaled_spacing());
1259 perimeter_min_spacing = std::min(perimeter_min_spacing, float(std::min(extflow.scaled_spacing(), flow.scaled_spacing())));
1260 }
1261 polygons_append(cache.holes, to_polygons(layerm.fill_expolygons()));
1262 }
1263 // Save some computing time by reducing the number of polygons.
1264 cache.top_surfaces = union_(cache.top_surfaces);
1265 cache.bottom_surfaces = union_(cache.bottom_surfaces);
1266 // For a multi-material print, simulate perimeter / infill split as if only a single extruder has been used for the whole print.
1267 if (perimeter_offset > 0.) {
1268 // The layer.lslices are forced to merge by expanding them first.
1269 polygons_append(cache.holes, offset2(layer.lslices, 0.3f * perimeter_min_spacing, - perimeter_offset - 0.3f * perimeter_min_spacing));
1270#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
1271 {
1272 Slic3r::SVG svg(debug_out_path("discover_vertical_shells-extra-holes-%d.svg", debug_idx), get_extents(layer.lslices));
1273 svg.draw(layer.lslices, "blue");
1274 svg.draw(union_ex(cache.holes), "red");
1275 svg.draw_outline(union_ex(cache.holes), "black", "blue", scale_(0.05));
1276 svg.Close();
1277 }
1278#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
1279 }
1280 cache.holes = union_(cache.holes);
1281 }
1282 });
1284 BOOST_LOG_TRIVIAL(debug) << "Discovering vertical shells in parallel - end : cache top / bottom";
1285 }
1286
1287 for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id) {
1288 //FIXME Improve the heuristics for a grain size.
1289 size_t grain_size = std::max(num_layers / 16, size_t(1));
1290
1291 if (! top_bottom_surfaces_all_regions) {
1292 // This is either a single material print, or a multi-material print and interface_shells are enabled, meaning that the vertical shell thickness
1293 // is calculated over a single material.
1294 BOOST_LOG_TRIVIAL(debug) << "Discovering vertical shells for region " << region_id << " in parallel - start : cache top / bottom";
1295 tbb::parallel_for(
1296 tbb::blocked_range<size_t>(0, num_layers, grain_size),
1297 [this, region_id, &cache_top_botom_regions](const tbb::blocked_range<size_t>& range) {
1298 PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
1299 const std::initializer_list<SurfaceType> surfaces_bottom { stBottom, stBottomBridge };
1300 for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) {
1302 Layer &layer = *m_layers[idx_layer];
1303 LayerRegion &layerm = *layer.m_regions[region_id];
1304 float top_bottom_expansion = float(layerm.flow(frSolidInfill).scaled_spacing()) * top_bottom_expansion_coeff;
1305 // Top surfaces.
1306 auto &cache = cache_top_botom_regions[idx_layer];
1307 cache.top_surfaces = offset(layerm.slices().filter_by_type(stTop), top_bottom_expansion);
1308// append(cache.top_surfaces, offset(layerm.fill_surfaces().filter_by_type(stTop), top_bottom_expansion));
1309 // Bottom surfaces.
1310 cache.bottom_surfaces = offset(layerm.slices().filter_by_types(surfaces_bottom), top_bottom_expansion);
1311// append(cache.bottom_surfaces, offset(layerm.fill_surfaces().filter_by_types(surfaces_bottom), top_bottom_expansion));
1312 // Holes over all regions. Only collect them once, they are valid for all region_id iterations.
1313 if (cache.holes.empty()) {
1314 for (size_t region_id = 0; region_id < layer.regions().size(); ++ region_id)
1315 polygons_append(cache.holes, to_polygons(layer.regions()[region_id]->fill_expolygons()));
1316 }
1317 }
1318 });
1320 BOOST_LOG_TRIVIAL(debug) << "Discovering vertical shells for region " << region_id << " in parallel - end : cache top / bottom";
1321 }
1322
1323 BOOST_LOG_TRIVIAL(debug) << "Discovering vertical shells for region " << region_id << " in parallel - start : ensure vertical wall thickness";
1324 grain_size = 1;
1325 tbb::parallel_for(
1326 tbb::blocked_range<size_t>(0, num_layers, grain_size),
1327 [this, region_id, &cache_top_botom_regions]
1328 (const tbb::blocked_range<size_t>& range) {
1329 PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
1330 // printf("discover_vertical_shells from %d to %d\n", range.begin(), range.end());
1331 for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) {
1333#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
1334 static size_t debug_idx = 0;
1335 ++ debug_idx;
1336#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
1337
1338 Layer *layer = m_layers[idx_layer];
1339 LayerRegion *layerm = layer->m_regions[region_id];
1340 const PrintRegionConfig &region_config = layerm->region().config();
1341
1342#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
1343 layerm->export_region_slices_to_svg_debug("3_discover_vertical_shells-initial");
1344 layerm->export_region_fill_surfaces_to_svg_debug("3_discover_vertical_shells-initial");
1345#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
1346
1347 Flow solid_infill_flow = layerm->flow(frSolidInfill);
1348 coord_t infill_line_spacing = solid_infill_flow.scaled_spacing();
1349 // Find a union of perimeters below / above this surface to guarantee a minimum shell thickness.
1350 Polygons shell;
1352#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
1353 ExPolygons shell_ex;
1354#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
1355 float min_perimeter_infill_spacing = float(infill_line_spacing) * 1.05f;
1356#if 0
1357// #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
1358 {
1359 Slic3r::SVG svg_cummulative(debug_out_path("discover_vertical_shells-perimeters-before-union-run%d.svg", debug_idx), this->bounding_box());
1360 for (int n = (int)idx_layer - n_extra_bottom_layers; n <= (int)idx_layer + n_extra_top_layers; ++ n) {
1361 if (n < 0 || n >= (int)m_layers.size())
1362 continue;
1363 ExPolygons &expolys = m_layers[n]->perimeter_expolygons;
1364 for (size_t i = 0; i < expolys.size(); ++ i) {
1365 Slic3r::SVG svg(debug_out_path("discover_vertical_shells-perimeters-before-union-run%d-layer%d-expoly%d.svg", debug_idx, n, i), get_extents(expolys[i]));
1366 svg.draw(expolys[i]);
1367 svg.draw_outline(expolys[i].contour, "black", scale_(0.05));
1368 svg.draw_outline(expolys[i].holes, "blue", scale_(0.05));
1369 svg.Close();
1370
1371 svg_cummulative.draw(expolys[i]);
1372 svg_cummulative.draw_outline(expolys[i].contour, "black", scale_(0.05));
1373 svg_cummulative.draw_outline(expolys[i].holes, "blue", scale_(0.05));
1374 }
1375 }
1376 }
1377#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
1378 polygons_append(holes, cache_top_botom_regions[idx_layer].holes);
1379 auto combine_holes = [&holes](const Polygons &holes2) {
1380 if (holes.empty() || holes2.empty())
1381 holes.clear();
1382 else
1383 holes = intersection(holes, holes2);
1384 };
1385 auto combine_shells = [&shell](const Polygons &shells2) {
1386 if (shell.empty())
1387 shell = std::move(shells2);
1388 else if (! shells2.empty()) {
1389 polygons_append(shell, shells2);
1390 // Running the union_ using the Clipper library piece by piece is cheaper
1391 // than running the union_ all at once.
1392 shell = union_(shell);
1393 }
1394 };
1395 static constexpr const bool one_more_layer_below_top_bottom_surfaces = false;
1396 if (int n_top_layers = region_config.top_solid_layers.value; n_top_layers > 0) {
1397 // Gather top regions projected to this layer.
1398 coordf_t print_z = layer->print_z;
1399 int i = int(idx_layer) + 1;
1400 int itop = int(idx_layer) + n_top_layers;
1401 bool at_least_one_top_projected = false;
1402 for (; i < int(cache_top_botom_regions.size()) &&
1403 (i < itop || m_layers[i]->print_z - print_z < region_config.top_solid_min_thickness - EPSILON);
1404 ++ i) {
1405 at_least_one_top_projected = true;
1406 const DiscoverVerticalShellsCacheEntry &cache = cache_top_botom_regions[i];
1407 combine_holes(cache.holes);
1408 combine_shells(cache.top_surfaces);
1409 }
1410 if (!at_least_one_top_projected && i < int(cache_top_botom_regions.size())) {
1411 // Lets consider this a special case - with only 1 top solid and minimal shell thickness settings, the
1412 // boundaries of solid layers are not anchored over/under perimeters, so lets fix it by adding at least one
1413 // perimeter width of area
1414 Polygons anchor_area = intersection(expand(cache_top_botom_regions[idx_layer].top_surfaces,
1415 layerm->flow(frExternalPerimeter).scaled_spacing()),
1416 to_polygons(m_layers[i]->lslices));
1417 combine_shells(anchor_area);
1418 }
1419
1420 if (one_more_layer_below_top_bottom_surfaces)
1421 if (i < int(cache_top_botom_regions.size()) &&
1422 (i <= itop || m_layers[i]->bottom_z() - print_z < region_config.top_solid_min_thickness - EPSILON))
1423 combine_holes(cache_top_botom_regions[i].holes);
1424 }
1425 if (int n_bottom_layers = region_config.bottom_solid_layers.value; n_bottom_layers > 0) {
1426 // Gather bottom regions projected to this layer.
1427 coordf_t bottom_z = layer->bottom_z();
1428 int i = int(idx_layer) - 1;
1429 int ibottom = int(idx_layer) - n_bottom_layers;
1430 bool at_least_one_bottom_projected = false;
1431 for (; i >= 0 &&
1432 (i > ibottom || bottom_z - m_layers[i]->bottom_z() < region_config.bottom_solid_min_thickness - EPSILON);
1433 -- i) {
1434 at_least_one_bottom_projected = true;
1435 const DiscoverVerticalShellsCacheEntry &cache = cache_top_botom_regions[i];
1436 combine_holes(cache.holes);
1437 combine_shells(cache.bottom_surfaces);
1438 }
1439
1440 if (!at_least_one_bottom_projected && i >= 0) {
1441 Polygons anchor_area = intersection(expand(cache_top_botom_regions[idx_layer].bottom_surfaces,
1442 layerm->flow(frExternalPerimeter).scaled_spacing()),
1443 to_polygons(m_layers[i]->lslices));
1444 combine_shells(anchor_area);
1445 }
1446
1447 if (one_more_layer_below_top_bottom_surfaces)
1448 if (i >= 0 &&
1449 (i > ibottom || bottom_z - m_layers[i]->print_z < region_config.bottom_solid_min_thickness - EPSILON))
1450 combine_holes(cache_top_botom_regions[i].holes);
1451 }
1452#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
1453 {
1454 Slic3r::SVG svg(debug_out_path("discover_vertical_shells-perimeters-before-union-%d.svg", debug_idx), get_extents(shell));
1455 svg.draw(shell);
1456 svg.draw_outline(shell, "black", scale_(0.05));
1457 svg.Close();
1458 }
1459#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
1460#if 0
1461// shell = union_(shell, true);
1462 shell = union_(shell, false);
1463#endif
1464#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
1465 shell_ex = union_safety_offset_ex(shell);
1466#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
1467
1468 //if (shell.empty())
1469 // continue;
1470
1471#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
1472 {
1473 Slic3r::SVG svg(debug_out_path("discover_vertical_shells-perimeters-after-union-%d.svg", debug_idx), get_extents(shell));
1474 svg.draw(shell_ex);
1475 svg.draw_outline(shell_ex, "black", "blue", scale_(0.05));
1476 svg.Close();
1477 }
1478#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
1479
1480#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
1481 {
1482 Slic3r::SVG svg(debug_out_path("discover_vertical_shells-internal-wshell-%d.svg", debug_idx), get_extents(shell));
1483 svg.draw(layerm->fill_surfaces().filter_by_type(stInternal), "yellow", 0.5);
1484 svg.draw_outline(layerm->fill_surfaces().filter_by_type(stInternal), "black", "blue", scale_(0.05));
1485 svg.draw(shell_ex, "blue", 0.5);
1486 svg.draw_outline(shell_ex, "black", "blue", scale_(0.05));
1487 svg.Close();
1488 }
1489 {
1490 Slic3r::SVG svg(debug_out_path("discover_vertical_shells-internalvoid-wshell-%d.svg", debug_idx), get_extents(shell));
1491 svg.draw(layerm->fill_surfaces().filter_by_type(stInternalVoid), "yellow", 0.5);
1492 svg.draw_outline(layerm->fill_surfaces().filter_by_type(stInternalVoid), "black", "blue", scale_(0.05));
1493 svg.draw(shell_ex, "blue", 0.5);
1494 svg.draw_outline(shell_ex, "black", "blue", scale_(0.05));
1495 svg.Close();
1496 }
1497 {
1498 Slic3r::SVG svg(debug_out_path("discover_vertical_shells-internalsolid-wshell-%d.svg", debug_idx), get_extents(shell));
1499 svg.draw(layerm->fill_surfaces().filter_by_type(stInternalSolid), "yellow", 0.5);
1500 svg.draw_outline(layerm->fill_surfaces().filter_by_type(stInternalSolid), "black", "blue", scale_(0.05));
1501 svg.draw(shell_ex, "blue", 0.5);
1502 svg.draw_outline(shell_ex, "black", "blue", scale_(0.05));
1503 svg.Close();
1504 }
1505#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
1506
1507 // Trim the shells region by the internal & internal void surfaces.
1508 const Polygons polygonsInternal = to_polygons(layerm->fill_surfaces().filter_by_types({ stInternal, stInternalVoid, stInternalSolid }));
1509 shell = intersection(shell, polygonsInternal, ApplySafetyOffset::Yes);
1510 polygons_append(shell, diff(polygonsInternal, holes));
1511 if (shell.empty())
1512 continue;
1513
1514 // Append the internal solids, so they will be merged with the new ones.
1515 polygons_append(shell, to_polygons(layerm->fill_surfaces().filter_by_type(stInternalSolid)));
1516
1517 // These regions will be filled by a rectilinear full infill. Currently this type of infill
1518 // only fills regions, which fit at least a single line. To avoid gaps in the sparse infill,
1519 // make sure that this region does not contain parts narrower than the infill spacing width.
1520#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
1521 Polygons shell_before = shell;
1522#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
1523 ExPolygons regularized_shell;
1524 {
1525 // Open to remove (filter out) regions narrower than a bit less than an infill extrusion line width.
1526 // Such narrow regions are difficult to fill in with a gap fill algorithm (or Arachne), however they are most likely
1527 // not needed for print stability / quality.
1528 const float narrow_ensure_vertical_wall_thickness_region_radius = 0.5f * 0.65f * min_perimeter_infill_spacing;
1529 // Then close gaps narrower than 1.2 * line width, such gaps are difficult to fill in with sparse infill,
1530 // thus they will be merged into the solid infill.
1531 const float narrow_sparse_infill_region_radius = 0.5f * 1.2f * min_perimeter_infill_spacing;
1532 // Finally expand the infill a bit to remove tiny gaps between solid infill and the other regions.
1533 const float tiny_overlap_radius = 0.2f * min_perimeter_infill_spacing;
1534 regularized_shell = shrink_ex(offset2_ex(union_ex(shell),
1535 // Open to remove (filter out) regions narrower than an infill extrusion line width.
1536 -narrow_ensure_vertical_wall_thickness_region_radius,
1537 // Then close gaps narrower than 1.2 * line width, such gaps are difficult to fill in with sparse infill.
1538 narrow_ensure_vertical_wall_thickness_region_radius + narrow_sparse_infill_region_radius, ClipperLib::jtSquare),
1539 // Finally expand the infill a bit to remove tiny gaps between solid infill and the other regions.
1540 narrow_sparse_infill_region_radius - tiny_overlap_radius, ClipperLib::jtSquare);
1541
1542 Polygons internal_volume;
1543 {
1544 Polygons shrinked_bottom_slice = idx_layer > 0 ? to_polygons(m_layers[idx_layer - 1]->lslices) : Polygons{};
1545 Polygons shrinked_upper_slice = (idx_layer + 1) < m_layers.size() ?
1546 to_polygons(m_layers[idx_layer + 1]->lslices) :
1547 Polygons{};
1548 internal_volume = intersection(shrinked_bottom_slice, shrinked_upper_slice);
1549 }
1550
1551 // The opening operation may cause scattered tiny drops on the smooth parts of the model, filter them out
1552 regularized_shell.erase(std::remove_if(regularized_shell.begin(), regularized_shell.end(),
1553 [&min_perimeter_infill_spacing, &internal_volume](const ExPolygon &p) {
1554 return p.area() < min_perimeter_infill_spacing * scaled(1.5) ||
1555 (p.area() < min_perimeter_infill_spacing * scaled(8.0) &&
1556 diff(to_polygons(p), internal_volume).empty());
1557 }),
1558 regularized_shell.end());
1559 }
1560 if (regularized_shell.empty())
1561 continue;
1562
1563 ExPolygons new_internal_solid = intersection_ex(polygonsInternal, regularized_shell);
1564#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
1565 {
1566 Slic3r::SVG svg(debug_out_path("discover_vertical_shells-regularized-%d.svg", debug_idx), get_extents(shell_before));
1567 // Source shell.
1568 svg.draw(union_safety_offset_ex(shell_before));
1569 // Shell trimmed to the internal surfaces.
1570 svg.draw_outline(union_safety_offset_ex(shell), "black", "blue", scale_(0.05));
1571 // Regularized infill region.
1572 svg.draw_outline(new_internal_solid, "red", "magenta", scale_(0.05));
1573 svg.Close();
1574 }
1575#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
1576
1577 // Trim the internal & internalvoid by the shell.
1578 Slic3r::ExPolygons new_internal = diff_ex(layerm->fill_surfaces().filter_by_type(stInternal), regularized_shell);
1579 Slic3r::ExPolygons new_internal_void = diff_ex(layerm->fill_surfaces().filter_by_type(stInternalVoid), regularized_shell);
1580
1581#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
1582 {
1583 SVG::export_expolygons(debug_out_path("discover_vertical_shells-new_internal-%d.svg", debug_idx), get_extents(shell), new_internal, "black", "blue", scale_(0.05));
1584 SVG::export_expolygons(debug_out_path("discover_vertical_shells-new_internal_void-%d.svg", debug_idx), get_extents(shell), new_internal_void, "black", "blue", scale_(0.05));
1585 SVG::export_expolygons(debug_out_path("discover_vertical_shells-new_internal_solid-%d.svg", debug_idx), get_extents(shell), new_internal_solid, "black", "blue", scale_(0.05));
1586 }
1587#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
1588
1589 // Assign resulting internal surfaces to layer.
1590 layerm->m_fill_surfaces.keep_types({ stTop, stBottom, stBottomBridge });
1591 layerm->m_fill_surfaces.append(new_internal, stInternal);
1592 layerm->m_fill_surfaces.append(new_internal_void, stInternalVoid);
1593 layerm->m_fill_surfaces.append(new_internal_solid, stInternalSolid);
1594 } // for each layer
1595 });
1597 BOOST_LOG_TRIVIAL(debug) << "Discovering vertical shells for region " << region_id << " in parallel - end";
1598
1599#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
1600 for (size_t idx_layer = 0; idx_layer < m_layers.size(); ++idx_layer) {
1601 LayerRegion *layerm = m_layers[idx_layer]->get_region(region_id);
1602 layerm->export_region_slices_to_svg_debug("3_discover_vertical_shells-final");
1603 layerm->export_region_fill_surfaces_to_svg_debug("3_discover_vertical_shells-final");
1604 }
1605#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
1606 } // for each region
1607} // void PrintObject::discover_vertical_shells()
BoundingBox bounding_box() const
Definition Print.hpp:261
Definition SVG.hpp:14
static void export_expolygons(const char *path, const BoundingBox &bbox, const Slic3r::ExPolygons &expolygons, std::string stroke_outer="black", std::string stroke_holes="blue", coordf_t stroke_width=0)
Definition SVG.cpp:309
double coordf_t
Definition libslic3r.h:45
@ jtSquare
Definition clipper.hpp:138
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half() max(const half &a, const half &b)
Definition Half.h:516
Slic3r::Polygons union_(const Slic3r::Polygons &subject)
Definition ClipperUtils.cpp:704
@ frExternalPerimeter
Definition Flow.hpp:17
ExPolygons offset2_ex(const ExPolygons &expolygons, const float delta1, const float delta2, ClipperLib::JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:576
Polygons offset2(const ExPolygons &expolygons, const float delta1, const float delta2, ClipperLib::JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:572
void append(std::vector< T, Alloc > &dest, const std::vector< T, Alloc2 > &src)
Definition libslic3r.h:110
Slic3r::ExPolygons shrink_ex(const Slic3r::Polygons &polygons, const float delta, ClipperLib::JoinType joinType=DefaultJoinType, double miterLimit=DefaultMiterLimit)
Definition ClipperUtils.hpp:374
const Polygon & contour(const ExPolygon &p)
Definition AGGRaster.hpp:21
const Polygons & holes(const ExPolygon &p)
Definition AGGRaster.hpp:22
const THolesContainer< PolygonImpl > & holes(const Slic3r::ExPolygon &sh)
Definition geometries.hpp:189
STL namespace.

References Slic3r::SurfaceCollection::append(), Slic3r::Layer::bottom_z(), Slic3r::SVG::Close(), Slic3r::PrintRegion::config(), Slic3r::debug_out_path(), Slic3r::diff(), Slic3r::diff_ex(), Slic3r::SVG::draw(), Slic3r::SVG::draw_outline(), EPSILON, Slic3r::expand(), Slic3r::LayerRegion::export_region_fill_surfaces_to_svg_debug(), Slic3r::LayerRegion::export_region_slices_to_svg_debug(), Slic3r::LayerRegion::fill_expolygons(), Slic3r::LayerRegion::fill_surfaces(), Slic3r::SurfaceCollection::filter_by_type(), Slic3r::SurfaceCollection::filter_by_types(), Slic3r::LayerRegion::flow(), Slic3r::frExternalPerimeter, Slic3r::frPerimeter, Slic3r::frSolidInfill, Slic3r::get_extents(), Slic3r::intersection(), Slic3r::intersection_ex(), ClipperLib::jtSquare, Slic3r::SurfaceCollection::keep_types(), Slic3r::log_memory_info(), Slic3r::Layer::lslices, Slic3r::LayerRegion::m_fill_surfaces, Slic3r::Layer::m_regions, Slic3r::offset2(), Slic3r::offset2_ex(), Slic3r::polygons_append(), PRINT_OBJECT_TIME_LIMIT_MILLIS, Slic3r::Layer::print_z, Slic3r::PrintRegionConfig, Slic3r::range(), Slic3r::LayerRegion::region(), Slic3r::Layer::regions(), scale_, Slic3r::Flow::scaled_spacing(), Slic3r::Flow::scaled_width(), Slic3r::shrink_ex(), Slic3r::LayerRegion::slices(), Slic3r::stBottom, Slic3r::stBottomBridge, Slic3r::stInternal, Slic3r::stInternalSolid, Slic3r::stInternalVoid, Slic3r::stTop, Slic3r::to_polygons(), Slic3r::union_(), Slic3r::union_ex(), and Slic3r::union_safety_offset_ex().

+ Here is the call graph for this function:

◆ enable_all_steps_unguarded()

void Slic3r::PrintObjectBaseWithState< Print , PrintObjectStep , COUNT >::enable_all_steps_unguarded ( bool  enable)
inlineprotectedinherited
785{ m_state.enable_all_unguarded(enable); }
void enable_all_unguarded(bool enable)
Definition PrintBase.hpp:154

◆ enable_step_unguarded()

void Slic3r::PrintObjectBaseWithState< Print , PrintObjectStep , COUNT >::enable_step_unguarded ( PrintObjectStepEnum  step,
bool  enable 
)
inlineprotectedinherited
784{ m_state.enable_unguarded(step, enable); }
void enable_unguarded(StepType step, bool enable)
Definition PrintBase.hpp:150

◆ estimate_curled_extrusions()

void Slic3r::PrintObject::estimate_curled_extrusions ( )
private
513{
515 if (this->print()->config().avoid_crossing_curled_overhangs ||
516 std::any_of(this->print()->m_print_regions.begin(), this->print()->m_print_regions.end(),
517 [](const PrintRegion *region) { return region->config().enable_dynamic_overhang_speeds.getBool(); })) {
518 BOOST_LOG_TRIVIAL(debug) << "Estimating areas with curled extrusions - start";
519 m_print->set_status(88, _u8L("Estimating curled extrusions"));
520
521 // Estimate curling of support material and add it to the malformaition lines of each layer
522 float support_flow_width = support_material_flow(this, this->config().layer_height).width();
523 SupportSpotsGenerator::Params params{this->print()->m_config.filament_type.values,
524 float(this->print()->m_config.perimeter_acceleration.getFloat()),
525 this->config().raft_layers.getInt(), this->config().brim_type.value,
526 float(this->config().brim_width.getFloat())};
530 BOOST_LOG_TRIVIAL(debug) << "Estimating areas with curled extrusions - end";
531 }
533 }
534}
#define _u8L(s)
macro used to mark string used at localization, return same string
Definition SLAPrint.cpp:29
float width() const
Definition Flow.hpp:60
void set_status(int percent, const std::string &message, unsigned int flags=SlicingStatus::DEFAULT)
Definition PrintBase.hpp:492
PrintConfig m_config
Definition Print.hpp:672
PrintRegionPtrs m_print_regions
Definition Print.hpp:676
bool set_started(PrintObjectStepEnum step)
Definition PrintBase.hpp:761
PrintStateBase::TimeStamp set_done(PrintObjectStepEnum step)
Definition PrintBase.hpp:763
auto support_layers() const
Definition Print.hpp:248
void estimate_supports_malformations(SupportLayerPtrs &layers, float flow_width, const Params &params)
Definition SupportSpotsGenerator.cpp:1089
void estimate_malformations(LayerPtrs &layers, const Params &params)
Definition SupportSpotsGenerator.cpp:1160
@ posEstimateCurledExtrusions
Definition Print.hpp:70
layer_height((ConfigOptionInt, faded_layers))((ConfigOptionFloat
Flow support_material_flow(const PrintObject *object, float layer_height)
Definition Flow.cpp:218

References _u8L, Slic3r::SupportSpotsGenerator::Params::filament_type, Slic3r::layer_height(), Slic3r::posEstimateCurledExtrusions, Slic3r::support_material_flow(), and Slic3r::Flow::width().

+ Here is the call graph for this function:

◆ finalize_impl()

void Slic3r::PrintObjectBaseWithState< Print , PrintObjectStep , COUNT >::finalize_impl ( )
inlineprotectedinherited
void mark_canceled_unguarded()
Definition PrintBase.hpp:308

◆ generate_new_id()

static ObjectID Slic3r::ObjectBase::generate_new_id ( )
inlinestaticprivateinherited
84{ return ObjectID(++ s_last_id); }
static size_t s_last_id
Definition ObjectID.hpp:85

References Slic3r::ObjectBase::s_last_id.

Referenced by Slic3r::ObjectBase::set_new_unique_id().

+ Here is the caller graph for this function:

◆ generate_support_material()

void Slic3r::PrintObject::generate_support_material ( )
private
492{
493 if (this->set_started(posSupportMaterial)) {
494 this->clear_support_layers();
495 if ((this->has_support() && m_layers.size() > 1) || (this->has_raft() && ! m_layers.empty())) {
496 m_print->set_status(70, _u8L("Generating support material"));
499 } else {
500#if 0
501 // Printing without supports. Empty layer means some objects or object parts are levitating,
502 // therefore they cannot be printed without supports.
503 for (const Layer *layer : m_layers)
504 if (layer->empty())
505 throw Slic3r::SlicingError("Levitating objects cannot be printed without supports.");
506#endif
507 }
509 }
510}
void _generate_support_material()
Definition PrintObject.cpp:2867
Definition avrdude-slic3r.cpp:16
bool empty(const BoundingBoxBase< PointType, PointsType > &bb)
Definition BoundingBox.hpp:229

References _u8L, and Slic3r::posSupportMaterial.

◆ generate_support_spots()

void Slic3r::PrintObject::generate_support_spots ( )
private
468{
470 BOOST_LOG_TRIVIAL(debug) << "Searching support spots - start";
471 m_print->set_status(65, _u8L("Searching support spots"));
472 if (!this->shared_regions()->generated_support_points.has_value()) {
473 PrintTryCancel cancel_func = m_print->make_try_cancel();
474 SupportSpotsGenerator::Params params{this->print()->m_config.filament_type.values,
475 float(this->print()->m_config.perimeter_acceleration.getFloat()),
476 this->config().raft_layers.getInt(), this->config().brim_type.value,
477 float(this->config().brim_width.getFloat())};
478 auto [supp_points, partial_objects] = SupportSpotsGenerator::full_search(this, cancel_func, params);
479 Transform3d po_transform = this->trafo_centered();
480 if (this->layer_count() > 0) {
481 po_transform = Geometry::translation_transform(Vec3d{0, 0, this->layers().front()->bottom_z()}) * po_transform;
482 }
483 this->m_shared_regions->generated_support_points = {po_transform, supp_points, partial_objects};
485 }
486 BOOST_LOG_TRIVIAL(debug) << "Searching support spots - end";
488 }
489}
PrintTryCancel make_try_cancel() const
Definition PrintBase.hpp:546
Transform3d trafo_centered() const
Definition Print.hpp:251
const PrintObjectRegions * shared_regions() const
Definition Print.hpp:316
std::optional< GeneratedSupportPoints > generated_support_points
Definition Print.hpp:221
void translation_transform(Transform3d &transform, const Vec3d &translation)
Definition Geometry.cpp:328
std::tuple< SupportPoints, PartialObjects > full_search(const PrintObject *po, const PrintTryCancel &cancel_func, const Params &params)
Definition SupportSpotsGenerator.cpp:1077
@ posSupportSpotsSearch
Definition Print.hpp:70

References _u8L, Slic3r::SupportSpotsGenerator::Params::filament_type, and Slic3r::posSupportSpotsSearch.

◆ get_first_layer_bellow_printz()

const Layer * Slic3r::PrintObject::get_first_layer_bellow_printz ( coordf_t  print_z,
coordf_t  epsilon 
) const
3119{
3120 coordf_t limit = print_z + epsilon;
3121 auto it = Slic3r::lower_bound_by_predicate(m_layers.begin(), m_layers.end(), [limit](const Layer *layer) { return layer->print_z < limit; });
3122 return (it == m_layers.begin()) ? nullptr : *(--it);
3123}
constexpr double epsilon()
Definition DoubleSlider.hpp:28
ForwardIt lower_bound_by_predicate(ForwardIt first, ForwardIt last, LowerThanKeyPredicate lower_than_key)
Definition libslic3r.h:203

References Slic3r::lower_bound_by_predicate().

Referenced by Slic3r::get_boundary().

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

◆ get_layer() [1/2]

Layer * Slic3r::PrintObject::get_layer ( int  idx)
inline
281{ return m_layers[idx]; }

References m_layers.

◆ get_layer() [2/2]

◆ get_layer_at_printz() [1/4]

Layer * Slic3r::PrintObject::get_layer_at_printz ( coordf_t  print_z)
3103{ return const_cast<Layer*>(std::as_const(*this).get_layer_at_printz(print_z)); }

◆ get_layer_at_printz() [2/4]

const Layer * Slic3r::PrintObject::get_layer_at_printz ( coordf_t  print_z) const
3096 {
3097 auto it = Slic3r::lower_bound_by_predicate(m_layers.begin(), m_layers.end(), [print_z](const Layer *layer) { return layer->print_z < print_z; });
3098 return (it == m_layers.end() || (*it)->print_z != print_z) ? nullptr : *it;
3099}

References Slic3r::lower_bound_by_predicate().

+ Here is the call graph for this function:

◆ get_layer_at_printz() [3/4]

Layer * Slic3r::PrintObject::get_layer_at_printz ( coordf_t  print_z,
coordf_t  epsilon 
)
3116{ return const_cast<Layer*>(std::as_const(*this).get_layer_at_printz(print_z, epsilon)); }

◆ get_layer_at_printz() [4/4]

const Layer * Slic3r::PrintObject::get_layer_at_printz ( coordf_t  print_z,
coordf_t  epsilon 
) const
3108 {
3109 coordf_t limit = print_z - epsilon;
3110 auto it = Slic3r::lower_bound_by_predicate(m_layers.begin(), m_layers.end(), [limit](const Layer *layer) { return layer->print_z < limit; });
3111 return (it == m_layers.end() || (*it)->print_z > print_z + epsilon) ? nullptr : *it;
3112}

References Slic3r::lower_bound_by_predicate().

+ Here is the call graph for this function:

◆ get_support_layer()

SupportLayer * Slic3r::PrintObject::get_support_layer ( int  idx)
inline
296{ return m_support_layers[idx]; }

References m_support_layers.

◆ has_brim()

bool Slic3r::PrintObject::has_brim ( ) const
inline
268 {
269 return this->config().brim_type != btNoBrim
270 && this->config().brim_width.value > 0.
271 && ! this->has_raft();
272 }
bool has_raft() const
Definition Print.hpp:319
@ btNoBrim
Definition PrintConfig.hpp:118

References Slic3r::btNoBrim, config(), and has_raft().

+ Here is the call graph for this function:

◆ has_raft()

bool Slic3r::PrintObject::has_raft ( ) const
inline
319{ return m_config.raft_layers > 0; }

References m_config.

Referenced by Slic3r::FFFTreeSupport::generate_raft_contact(), has_brim(), has_support_material(), and Slic3r::Print::validate().

+ Here is the caller graph for this function:

◆ has_support()

bool Slic3r::PrintObject::has_support ( ) const
inline
318{ return m_config.support_material || m_config.support_material_enforce_layers > 0; }

References m_config.

Referenced by has_support_material(), and Slic3r::Print::validate().

+ Here is the caller graph for this function:

◆ has_support_material()

bool Slic3r::PrintObject::has_support_material ( ) const
inline
320{ return this->has_support() || this->has_raft(); }

References has_raft(), and has_support().

Referenced by Slic3r::Print::validate().

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

◆ height()

coord_t Slic3r::PrintObject::height ( ) const
inline
264{ return m_size.z(); }

References m_size.

Referenced by Slic3r::SupportSpotsGenerator::SupportGridFilter::SupportGridFilter().

+ Here is the caller graph for this function:

◆ id()

ObjectID Slic3r::ObjectBase::id ( ) const
inlineinherited
55{ return m_id; }

References Slic3r::ObjectBase::m_id.

Referenced by Slic3r::Model::Model(), Slic3r::ModelInstance::ModelInstance(), Slic3r::ModelMaterial::ModelMaterial(), Slic3r::ModelObject::ModelObject(), Slic3r::ModelObject::ModelObject(), Slic3r::ModelObject::ModelObject(), Slic3r::ModelObject::ModelObject(), Slic3r::ModelObject::ModelObject(), Slic3r::ModelVolume::ModelVolume(), Slic3r::ModelVolume::ModelVolume(), Slic3r::ModelVolume::ModelVolume(), Slic3r::_3MF_Importer::_load_model_from_file(), Slic3r::GUI::Plater::priv::actualize_slicing_warnings(), Slic3r::ModelObjectStatusDB::add(), Slic3r::ModelObjectStatusDB::add_if_new(), Slic3r::Print::apply(), Slic3r::SLAPrint::apply(), Slic3r::GUI::GLGizmoFdmSupports::apply_data_from_backend(), Slic3r::ModelVolume::check(), Slic3r::check_model_ids_equal(), Slic3r::ModelObject::convert_units(), Slic3r::ObjectBase::copy_id(), Slic3r::PrintObjectStatusDB::count(), anonymous_namespace{RaycastManager.cpp}::create_key(), priv::create_volume(), Slic3r::GUI::Emboss::create_volume_sources(), Slic3r::GUI::GLGizmoHollow::data_changed(), Slic3r::GUI::GLGizmoPainterBase::data_changed(), Slic3r::GUI::GLGizmoSlaSupports::data_changed(), Slic3r::Model::delete_object(), Slic3r::GUI::Plater::export_stl_obj(), Slic3r::ModelObjectStatusDB::get(), Slic3r::GUI::get_arrange_poly(), Slic3r::GUI::GLGizmoSlaSupports::get_data_from_backend(), Slic3r::PrintObjectStatusDB::get_range(), Slic3r::GUI::GLGizmoFdmSupports::has_backend_supports(), Slic3r::GUI::GLGizmoSlaSupports::has_backend_supports(), Slic3r::CutObjectBase::has_same_id(), Slic3r::UndoRedo::StackImpl::immutable_object_id_impl(), Slic3r::GUI::GLGizmoSimplify::init_model(), Slic3r::inner_brim_area(), Slic3r::ModelObject::is_cut(), Slic3r::CutObjectBase::is_equal(), Slic3r::ObjectBase::load_and_construct(), Slic3r::UndoRedo::StackImpl::load_snapshot(), Slic3r::GUI::ObjectList::merge(), Slic3r::model_property_changed(), Slic3r::model_volume_list_changed(), Slic3r::model_volume_list_copy_configs(), Slic3r::ModelConfigObject::object_id_and_timestamp_match(), Slic3r::ObjectWithTimestamp::object_id_and_timestamp_match(), Slic3r::GUI::GLGizmoEmboss::on_mouse_change_selection(), Slic3r::GUI::CommonGizmosDataObjects::SelectionInfo::on_update(), Slic3r::CutObjectBase::operator<(), Slic3r::Model::operator=(), Slic3r::ModelObject::operator=(), Slic3r::ModelObject::operator=(), Slic3r::CutObjectBase::operator==(), Slic3r::GUI::GLGizmoCut3D::perform_cut(), Slic3r::GUI::GLGizmoEmboss::process(), Slic3r::GUI::processed_objects_idxs(), Slic3r::GUI::GLCanvas3D::reload_scene(), Slic3r::GUI::GLCanvas3D::LayersEditing::select_object(), Slic3r::ModelMaterial::serialize(), Slic3r::SLAPrintObject::SliceRecord::set_model_slice_idx(), Slic3r::SLAPrintObject::SliceRecord::set_support_slice_idx(), Slic3r::slices_to_regions(), Slic3r::ModelObject::split(), Slic3r::UndoRedo::StackImpl::take_snapshot(), Slic3r::top_level_outer_brim_area(), Slic3r::GUI::update_object_cut_id(), and anonymous_namespace{EmbossJob.cpp}::update_volume_name().

◆ infill()

void Slic3r::PrintObject::infill ( )
private
416{
417 // prerequisites
418 this->prepare_infill();
419
420 if (this->set_started(posInfill)) {
421 // TRN Status for the Print calculation
422 m_print->set_status(45, _u8L("Making infill"));
423 const auto& adaptive_fill_octree = this->m_adaptive_fill_octrees.first;
424 const auto& support_fill_octree = this->m_adaptive_fill_octrees.second;
425
426 BOOST_LOG_TRIVIAL(debug) << "Filling layers in parallel - start";
427 tbb::parallel_for(
428 tbb::blocked_range<size_t>(0, m_layers.size()),
429 [this, &adaptive_fill_octree = adaptive_fill_octree, &support_fill_octree = support_fill_octree](const tbb::blocked_range<size_t>& range) {
430 PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
431 for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
432 m_print->throw_if_canceled();
433 m_layers[layer_idx]->make_fills(adaptive_fill_octree.get(), support_fill_octree.get(), this->m_lightning_generator.get());
434 }
435 }
436 );
438 BOOST_LOG_TRIVIAL(debug) << "Filling layers in parallel - end";
439 /* we could free memory now, but this would make this step not idempotent
440 ### $_->fill_surfaces->clear for map @{$_->regions}, @{$object->layers};
441 */
442 this->set_done(posInfill);
443 }
444}
void prepare_infill()
Definition PrintObject.cpp:271

References _u8L, Slic3r::posInfill, and Slic3r::range().

+ Here is the call graph for this function:

◆ insert_support_layer()

SupportLayerPtrs::iterator Slic3r::PrintObject::insert_support_layer ( SupportLayerPtrs::iterator  pos,
size_t  id,
size_t  interface_id,
coordf_t  height,
coordf_t  print_z,
coordf_t  slice_z 
)
619{
620 return m_support_layers.insert(pos, new SupportLayer(id, interface_id, this, height, print_z, slice_z));
621}

◆ instances()

const PrintInstances & Slic3r::PrintObject::instances ( ) const
inline
253{ return m_instances; }
std::vector< PrintInstance > m_instances
Definition Print.hpp:400

References m_instances.

Referenced by PrintObject(), Slic3r::GUI::GLCanvas3D::_load_print_object_toolpaths(), Slic3r::get_print_object_extrusions_extents(), Slic3r::has_polygons_nothing_inside(), Slic3r::GCode::process_layer_single_object(), set_instances(), and Slic3r::GCode::sort_print_object_instances().

+ Here is the caller graph for this function:

◆ invalidate_all_steps()

bool Slic3r::PrintObject::invalidate_all_steps ( )
private
877{
878 // First call the "invalidate" functions, which may cancel background processing.
880 // Then reset some of the depending values.
881 m_slicing_params.valid = false;
882 return result;
883}
bool invalidate_all_steps()
Definition PrintBase.hpp:602
bool valid
Definition Slicing.hpp:47

◆ invalidate_state_by_config_options()

bool Slic3r::PrintObject::invalidate_state_by_config_options ( const ConfigOptionResolver old_config,
const ConfigOptionResolver new_config,
const std::vector< t_config_option_key > &  opt_keys 
)
private
627{
628 if (opt_keys.empty())
629 return false;
630
631 std::vector<PrintObjectStep> steps;
632 bool invalidated = false;
633 for (const t_config_option_key &opt_key : opt_keys) {
634 if ( opt_key == "brim_width"
635 || opt_key == "brim_separation"
636 || opt_key == "brim_type") {
637 steps.emplace_back(posSupportSpotsSearch);
638 // Brim is printed below supports, support invalidates brim and skirt.
639 steps.emplace_back(posSupportMaterial);
640 } else if (
641 opt_key == "perimeters"
642 || opt_key == "extra_perimeters"
643 || opt_key == "extra_perimeters_on_overhangs"
644 || opt_key == "first_layer_extrusion_width"
645 || opt_key == "perimeter_extrusion_width"
646 || opt_key == "infill_overlap"
647 || opt_key == "external_perimeters_first") {
648 steps.emplace_back(posPerimeters);
649 } else if (
650 opt_key == "gap_fill_enabled"
651 || opt_key == "gap_fill_speed") {
652 // Return true if gap-fill speed has changed from zero value to non-zero or from non-zero value to zero.
653 auto is_gap_fill_changed_state_due_to_speed = [&opt_key, &old_config, &new_config]() -> bool {
654 if (opt_key == "gap_fill_speed") {
655 const auto *old_gap_fill_speed = old_config.option<ConfigOptionFloat>(opt_key);
656 const auto *new_gap_fill_speed = new_config.option<ConfigOptionFloat>(opt_key);
657 assert(old_gap_fill_speed && new_gap_fill_speed);
658 return (old_gap_fill_speed->value > 0.f && new_gap_fill_speed->value == 0.f) ||
659 (old_gap_fill_speed->value == 0.f && new_gap_fill_speed->value > 0.f);
660 }
661 return false;
662 };
663
664 // Filtering of unprintable regions in multi-material segmentation depends on if gap-fill is enabled or not.
665 // So step posSlice is invalidated when gap-fill was enabled/disabled by option "gap_fill_enabled" or by
666 // changing "gap_fill_speed" to force recomputation of the multi-material segmentation.
667 if (this->is_mm_painted() && (opt_key == "gap_fill_enabled" || (opt_key == "gap_fill_speed" && is_gap_fill_changed_state_due_to_speed())))
668 steps.emplace_back(posSlice);
669 steps.emplace_back(posPerimeters);
670 } else if (
671 opt_key == "layer_height"
672 || opt_key == "mmu_segmented_region_max_width"
673 || opt_key == "raft_layers"
674 || opt_key == "raft_contact_distance"
675 || opt_key == "slice_closing_radius"
676 || opt_key == "slicing_mode") {
677 steps.emplace_back(posSlice);
678 } else if (
679 opt_key == "elefant_foot_compensation"
680 || opt_key == "support_material_contact_distance"
681 || opt_key == "xy_size_compensation") {
682 steps.emplace_back(posSlice);
683 } else if (opt_key == "support_material") {
684 steps.emplace_back(posSupportMaterial);
685 if (m_config.support_material_contact_distance == 0.) {
686 // Enabling / disabling supports while soluble support interface is enabled.
687 // This changes the bridging logic (bridging enabled without supports, disabled with supports).
688 // Reset everything.
689 // See GH #1482 for details.
690 steps.emplace_back(posSlice);
691 }
692 } else if (
693 opt_key == "support_material_auto"
694 || opt_key == "support_material_angle"
695 || opt_key == "support_material_buildplate_only"
696 || opt_key == "support_material_enforce_layers"
697 || opt_key == "support_material_extruder"
698 || opt_key == "support_material_extrusion_width"
699 || opt_key == "support_material_bottom_contact_distance"
700 || opt_key == "support_material_interface_layers"
701 || opt_key == "support_material_bottom_interface_layers"
702 || opt_key == "support_material_interface_pattern"
703 || opt_key == "support_material_interface_contact_loops"
704 || opt_key == "support_material_interface_extruder"
705 || opt_key == "support_material_interface_spacing"
706 || opt_key == "support_material_pattern"
707 || opt_key == "support_material_style"
708 || opt_key == "support_material_xy_spacing"
709 || opt_key == "support_material_spacing"
710 || opt_key == "support_material_closing_radius"
711 || opt_key == "support_material_synchronize_layers"
712 || opt_key == "support_material_threshold"
713 || opt_key == "support_material_with_sheath"
714 || opt_key == "support_tree_angle"
715 || opt_key == "support_tree_angle_slow"
716 || opt_key == "support_tree_branch_diameter"
717 || opt_key == "support_tree_branch_diameter_angle"
718 || opt_key == "support_tree_branch_diameter_double_wall"
719 || opt_key == "support_tree_top_rate"
720 || opt_key == "support_tree_branch_distance"
721 || opt_key == "support_tree_tip_diameter"
722 || opt_key == "raft_expansion"
723 || opt_key == "raft_first_layer_density"
724 || opt_key == "raft_first_layer_expansion"
725 || opt_key == "dont_support_bridges"
726 || opt_key == "first_layer_extrusion_width") {
727 steps.emplace_back(posSupportMaterial);
728 } else if (opt_key == "bottom_solid_layers") {
729 steps.emplace_back(posPrepareInfill);
730 if (m_print->config().spiral_vase) {
731 // Changing the number of bottom layers when a spiral vase is enabled requires re-slicing the object again.
732 // Otherwise, holes in the bottom layers could be filled, as is reported in GH #5528.
733 steps.emplace_back(posSlice);
734 }
735 } else if (
736 opt_key == "interface_shells"
737 || opt_key == "infill_only_where_needed"
738 || opt_key == "infill_every_layers"
739 || opt_key == "solid_infill_every_layers"
740 || opt_key == "bottom_solid_min_thickness"
741 || opt_key == "top_solid_layers"
742 || opt_key == "top_solid_min_thickness"
743 || opt_key == "solid_infill_below_area"
744 || opt_key == "infill_extruder"
745 || opt_key == "solid_infill_extruder"
746 || opt_key == "infill_extrusion_width"
747 || opt_key == "bridge_angle") {
748 steps.emplace_back(posPrepareInfill);
749 } else if (
750 opt_key == "top_fill_pattern"
751 || opt_key == "bottom_fill_pattern"
752 || opt_key == "external_fill_link_max_length"
753 || opt_key == "fill_angle"
754 || opt_key == "infill_anchor"
755 || opt_key == "infill_anchor_max"
756 || opt_key == "top_infill_extrusion_width"
757 || opt_key == "first_layer_extrusion_width") {
758 steps.emplace_back(posInfill);
759 } else if (opt_key == "fill_pattern") {
760 steps.emplace_back(posPrepareInfill);
761 } else if (opt_key == "fill_density") {
762 // One likely wants to reslice only when switching between zero infill to simulate boolean difference (subtracting volumes),
763 // normal infill and 100% (solid) infill.
764 const auto *old_density = old_config.option<ConfigOptionPercent>(opt_key);
765 const auto *new_density = new_config.option<ConfigOptionPercent>(opt_key);
766 assert(old_density && new_density);
767 //FIXME Vojtech is not quite sure about the 100% here, maybe it is not needed.
768 if (is_approx(old_density->value, 0.) || is_approx(old_density->value, 100.) ||
769 is_approx(new_density->value, 0.) || is_approx(new_density->value, 100.))
770 steps.emplace_back(posPerimeters);
771 steps.emplace_back(posPrepareInfill);
772 } else if (opt_key == "solid_infill_extrusion_width") {
773 // This value is used for calculating perimeter - infill overlap, thus perimeters need to be recalculated.
774 steps.emplace_back(posPerimeters);
775 steps.emplace_back(posPrepareInfill);
776 } else if (
777 opt_key == "external_perimeter_extrusion_width"
778 || opt_key == "perimeter_extruder"
779 || opt_key == "fuzzy_skin"
780 || opt_key == "fuzzy_skin_thickness"
781 || opt_key == "fuzzy_skin_point_dist"
782 || opt_key == "overhangs"
783 || opt_key == "thin_walls"
784 || opt_key == "thick_bridges") {
785 steps.emplace_back(posPerimeters);
786 steps.emplace_back(posSupportMaterial);
787 } else if (opt_key == "bridge_flow_ratio") {
788 if (m_config.support_material_contact_distance > 0.) {
789 // Only invalidate due to bridging if bridging is enabled.
790 // If later "support_material_contact_distance" is modified, the complete PrintObject is invalidated anyway.
791 steps.emplace_back(posPerimeters);
792 steps.emplace_back(posInfill);
793 steps.emplace_back(posSupportMaterial);
794 }
795 } else if (
796 opt_key == "perimeter_generator"
797 || opt_key == "wall_transition_length"
798 || opt_key == "wall_transition_filter_deviation"
799 || opt_key == "wall_transition_angle"
800 || opt_key == "wall_distribution_count"
801 || opt_key == "min_feature_size"
802 || opt_key == "min_bead_width") {
803 steps.emplace_back(posSlice);
804 } else if (
805 opt_key == "seam_position"
806 || opt_key == "seam_preferred_direction"
807 || opt_key == "seam_preferred_direction_jitter"
808 || opt_key == "support_material_speed"
809 || opt_key == "support_material_interface_speed"
810 || opt_key == "bridge_speed"
811 || opt_key == "enable_dynamic_overhang_speeds"
812 || opt_key == "overhang_speed_0"
813 || opt_key == "overhang_speed_1"
814 || opt_key == "overhang_speed_2"
815 || opt_key == "overhang_speed_3"
816 || opt_key == "external_perimeter_speed"
817 || opt_key == "infill_speed"
818 || opt_key == "perimeter_speed"
819 || opt_key == "small_perimeter_speed"
820 || opt_key == "solid_infill_speed"
821 || opt_key == "top_solid_infill_speed") {
822 invalidated |= m_print->invalidate_step(psGCodeExport);
823 } else if (
824 opt_key == "wipe_into_infill"
825 || opt_key == "wipe_into_objects") {
826 invalidated |= m_print->invalidate_step(psWipeTower);
827 invalidated |= m_print->invalidate_step(psGCodeExport);
828 } else {
829 // for legacy, if we can't handle this option let's invalidate all steps
830 this->invalidate_all_steps();
831 invalidated = true;
832 }
833 }
834
836 for (PrintObjectStep step : steps)
837 invalidated |= this->invalidate_step(step);
838 return invalidated;
839}
bool invalidate_step(PrintStep step)
Definition Print.cpp:258
bool invalidate_step(PrintObjectStep step)
Definition PrintObject.cpp:841
bool invalidate_all_steps()
Definition PrintObject.cpp:876
bool is_mm_painted() const
Definition Print.hpp:322
ConfigOptionFloat
Definition PrintConfig.hpp:570
PrintObjectStep
Definition Print.hpp:68
@ posSlice
Definition Print.hpp:69
@ posPerimeters
Definition Print.hpp:69
@ posPrepareInfill
Definition Print.hpp:69
std::string t_config_option_key
Definition Config.hpp:76
@ psWipeTower
Definition Print.hpp:54
@ psGCodeExport
Definition Print.hpp:64
constexpr bool is_approx(Number value, Number test_value, Number precision=EPSILON)
Definition libslic3r.h:271
void sort_remove_duplicates(std::vector< T > &vec)
Definition libslic3r.h:188
Coord step(const Coord &crd, Dir d)
Definition MarchingSquares.hpp:137

References Slic3r::is_approx(), Slic3r::ConfigOptionResolver::option(), Slic3r::posInfill, Slic3r::posPerimeters, Slic3r::posPrepareInfill, Slic3r::posSlice, Slic3r::posSupportMaterial, Slic3r::posSupportSpotsSearch, Slic3r::psGCodeExport, Slic3r::psWipeTower, Slic3r::sort_remove_duplicates(), and Slic3r::ConfigOptionSingle< T >::value.

+ Here is the call graph for this function:

◆ invalidate_step()

bool Slic3r::PrintObject::invalidate_step ( PrintObjectStep  step)
private
842{
843 bool invalidated = Inherited::invalidate_step(step);
844
845 // propagate to dependent steps
846 if (step == posPerimeters) {
848 invalidated |= m_print->invalidate_steps({ psSkirtBrim });
849 } else if (step == posPrepareInfill) {
851 } else if (step == posInfill) {
852 invalidated |= this->invalidate_steps({ posIroning, posSupportSpotsSearch });
853 invalidated |= m_print->invalidate_steps({ psSkirtBrim });
854 } else if (step == posSlice) {
857 invalidated |= m_print->invalidate_steps({ psSkirtBrim });
858 m_slicing_params.valid = false;
859 } else if (step == posSupportMaterial) {
860 invalidated |= m_print->invalidate_steps({ psSkirtBrim, });
861 invalidated |= this->invalidate_steps({ posEstimateCurledExtrusions });
862 m_slicing_params.valid = false;
863 }
864
865 // invalidate alerts step always, since it depends on everything (except supports, but with supports enabled it is skipped anyway.)
867 // Wipe tower depends on the ordering of extruders, which in turn depends on everything.
868 // It also decides about what the wipe_into_infill / wipe_into_object features will do,
869 // and that too depends on many of the settings.
870 invalidated |= m_print->invalidate_step(psWipeTower);
871 // Invalidate G-code export in any case.
872 invalidated |= m_print->invalidate_step(psGCodeExport);
873 return invalidated;
874}
bool invalidate_steps(StepTypeIterator step_begin, StepTypeIterator step_end)
Definition PrintBase.hpp:598
bool invalidate_step(PrintObjectStepEnum step)
Definition PrintBase.hpp:770
bool invalidate_steps(StepTypeIterator step_begin, StepTypeIterator step_end)
Definition PrintBase.hpp:773
@ posIroning
Definition Print.hpp:70
@ psAlertWhenSupportsNeeded
Definition Print.hpp:59
@ psSkirtBrim
Definition Print.hpp:60

References Slic3r::posEstimateCurledExtrusions, Slic3r::posInfill, Slic3r::posIroning, Slic3r::posPerimeters, Slic3r::posPrepareInfill, Slic3r::posSlice, Slic3r::posSupportMaterial, Slic3r::posSupportSpotsSearch, Slic3r::psAlertWhenSupportsNeeded, Slic3r::psGCodeExport, Slic3r::psSkirtBrim, and Slic3r::psWipeTower.

◆ invalidate_steps() [1/2]

bool Slic3r::PrintObjectBaseWithState< Print , PrintObjectStep , COUNT >::invalidate_steps ( std::initializer_list< PrintObjectStepEnum il)
inlineprotectedinherited
776 { return m_state.invalidate_multiple(il.begin(), il.end(), PrintObjectBase::cancel_callback(m_print)); }
bool invalidate_multiple(StepTypeIterator step_begin, StepTypeIterator step_end, CancelationCallback cancel)
Definition PrintBase.hpp:249

◆ invalidate_steps() [2/2]

bool Slic3r::PrintObjectBaseWithState< Print , PrintObjectStep , COUNT >::invalidate_steps ( StepTypeIterator  step_begin,
StepTypeIterator  step_end 
)
inlineprotectedinherited
774 { return m_state.invalidate_multiple(step_begin, step_end, PrintObjectBase::cancel_callback(m_print)); }

◆ ironing()

void Slic3r::PrintObject::ironing ( )
private
447{
448 if (this->set_started(posIroning)) {
449 BOOST_LOG_TRIVIAL(debug) << "Ironing in parallel - start";
450 tbb::parallel_for(
451 // Ironing starting with layer 0 to support ironing all surfaces.
452 tbb::blocked_range<size_t>(0, m_layers.size()),
453 [this](const tbb::blocked_range<size_t>& range) {
454 PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
455 for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
456 m_print->throw_if_canceled();
457 m_layers[layer_idx]->make_ironing();
458 }
459 }
460 );
462 BOOST_LOG_TRIVIAL(debug) << "Ironing in parallel - end";
463 this->set_done(posIroning);
464 }
465}

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

+ Here is the call graph for this function:

◆ is_mm_painted()

bool Slic3r::PrintObject::is_mm_painted ( ) const
inline
322{ return this->model_object()->is_mm_painted(); }
bool is_mm_painted() const
Definition Model.cpp:800

References Slic3r::ModelObject::is_mm_painted(), and Slic3r::PrintObjectBase::model_object().

Referenced by Slic3r::Print::apply().

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

◆ is_step_done()

bool Slic3r::PrintObjectBaseWithState< Print , PrintObjectStep , COUNT >::is_step_done ( PrintObjectStepEnum  step) const
inlineinherited
739{ return m_state.is_done(step, PrintObjectBase::state_mutex(m_print)); }
bool is_done(StepType step, std::mutex &mtx) const
Definition PrintBase.hpp:134

◆ is_step_done_unguarded()

bool Slic3r::PrintObjectBaseWithState< Print , PrintObjectStep , COUNT >::is_step_done_unguarded ( PrintObjectStepEnum  step) const
inlineprotectedinherited
781{ return m_state.is_done_unguarded(step); }
bool is_done_unguarded(StepType step) const
Definition PrintBase.hpp:146

◆ is_step_enabled_unguarded()

bool Slic3r::PrintObjectBaseWithState< Print , PrintObjectStep , COUNT >::is_step_enabled_unguarded ( PrintObjectStepEnum  step) const
inlineprotectedinherited
783{ return m_state.is_enabled_unguarded(step); }
bool is_enabled_unguarded(StepType step) const
Definition PrintBase.hpp:159

◆ is_step_started_unguarded()

bool Slic3r::PrintObjectBaseWithState< Print , PrintObjectStep , COUNT >::is_step_started_unguarded ( PrintObjectStepEnum  step) const
inlineprotectedinherited
780{ return m_state.is_started_unguarded(step); }
bool is_started_unguarded(StepType step) const
Definition PrintBase.hpp:142

◆ last_completed_step()

auto Slic3r::PrintObjectBaseWithState< Print , PrintObjectStep , COUNT >::last_completed_step ( ) const
inlineinherited
744 {
745 static_assert(COUNT > 0, "Step count should be > 0");
746 auto s = int(COUNT) - 1;
747
748 std::lock_guard lk(state_mutex(m_print));
749 while (s >= 0 && ! is_step_done_unguarded(PrintObjectStepEnum(s)))
750 --s;
751
752 if (s < 0)
753 s = COUNT;
754
755 return PrintObjectStepEnum(s);
756 }
static std::mutex & state_mutex(PrintBase *print)
Definition PrintBase.cpp:110
bool is_step_done_unguarded(PrintObjectStepEnum step) const
Definition PrintBase.hpp:781
PrintObjectStep PrintObjectStepEnum
Definition PrintBase.hpp:732

◆ layer_count()

◆ layers() [1/2]

LayerPtrs & Slic3r::PrintObject::layers ( )
inline
256{ return m_layers; }

References m_layers.

◆ layers() [2/2]

◆ load_and_construct()

template<class Archive >
static void Slic3r::ObjectBase::load_and_construct ( Archive &  ar,
cereal::construct< ObjectBase > &  construct 
)
inlinestaticprivateinherited
96{ ObjectID id; ar(id); construct(id); }
ObjectID id() const
Definition ObjectID.hpp:55

References Slic3r::ObjectBase::id().

+ Here is the call graph for this function:

◆ make_perimeters()

void Slic3r::PrintObject::make_perimeters ( )
private
162{
163 // prerequisites
164 this->slice();
165
166 if (! this->set_started(posPerimeters))
167 return;
168
169 m_print->set_status(20, _u8L("Generating perimeters"));
170 BOOST_LOG_TRIVIAL(info) << "Generating perimeters..." << log_memory_info();
171
172 // Revert the typed slices into untyped slices.
173 if (m_typed_slices) {
174 for (Layer *layer : m_layers) {
175 layer->clear_fills();
176 layer->restore_untyped_slices();
178 }
179 m_typed_slices = false;
180 }
181
182 // compare each layer to the one below, and mark those slices needing
183 // one additional inner perimeter, like the top of domed objects-
184
185 // this algorithm makes sure that at least one perimeter is overlapping
186 // but we don't generate any extra perimeter if fill density is zero, as they would be floating
187 // inside the object - infill_only_where_needed should be the method of choice for printing
188 // hollow objects
189 for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id) {
190 const PrintRegion &region = this->printing_region(region_id);
191 if (! region.config().extra_perimeters || region.config().perimeters == 0 || region.config().fill_density == 0 || this->layer_count() < 2)
192 continue;
193
194 BOOST_LOG_TRIVIAL(debug) << "Generating extra perimeters for region " << region_id << " in parallel - start";
195 tbb::parallel_for(
196 tbb::blocked_range<size_t>(0, m_layers.size() - 1),
197 [this, &region, region_id](const tbb::blocked_range<size_t>& range) {
198 PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
199 for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
200 m_print->throw_if_canceled();
201 LayerRegion &layerm = *m_layers[layer_idx]->get_region(region_id);
202 const LayerRegion &upper_layerm = *m_layers[layer_idx+1]->get_region(region_id);
203 const Polygons upper_layerm_polygons = to_polygons(upper_layerm.slices().surfaces);
204 // Filter upper layer polygons in intersection_ppl by their bounding boxes?
205 // my $upper_layerm_poly_bboxes= [ map $_->bounding_box, @{$upper_layerm_polygons} ];
206 const double total_loop_length = total_length(upper_layerm_polygons);
207 const coord_t perimeter_spacing = layerm.flow(frPerimeter).scaled_spacing();
208 const Flow ext_perimeter_flow = layerm.flow(frExternalPerimeter);
209 const coord_t ext_perimeter_width = ext_perimeter_flow.scaled_width();
210 const coord_t ext_perimeter_spacing = ext_perimeter_flow.scaled_spacing();
211
212 // slice is not const because slice.extra_perimeters is being incremented.
213 for (Surface &slice : layerm.m_slices.surfaces) {
214 for (;;) {
215 // compute the total thickness of perimeters
216 const coord_t perimeters_thickness = ext_perimeter_width/2 + ext_perimeter_spacing/2
217 + (region.config().perimeters-1 + slice.extra_perimeters) * perimeter_spacing;
218 // define a critical area where we don't want the upper slice to fall into
219 // (it should either lay over our perimeters or outside this area)
220 const coord_t critical_area_depth = coord_t(perimeter_spacing * 1.5);
221 const Polygons critical_area = diff(
222 offset(slice.expolygon, float(- perimeters_thickness)),
223 offset(slice.expolygon, float(- perimeters_thickness - critical_area_depth))
224 );
225 // check whether a portion of the upper slices falls inside the critical area
226 const Polylines intersection = intersection_pl(to_polylines(upper_layerm_polygons), critical_area);
227 // only add an additional loop if at least 30% of the slice loop would benefit from it
228 if (total_length(intersection) <= total_loop_length*0.3)
229 break;
230 /*
231 if (0) {
232 require "Slic3r/SVG.pm";
233 Slic3r::SVG::output(
234 "extra.svg",
235 no_arrows => 1,
236 expolygons => union_ex($critical_area),
237 polylines => [ map $_->split_at_first_point, map $_->p, @{$upper_layerm->slices} ],
238 );
239 }
240 */
241 ++ slice.extra_perimeters;
242 }
243 #ifdef DEBUG
244 if (slice.extra_perimeters > 0)
245 printf(" adding %d more perimeter(s) at layer %zu\n", slice.extra_perimeters, layer_idx);
246 #endif
247 }
248 }
249 });
251 BOOST_LOG_TRIVIAL(debug) << "Generating extra perimeters for region " << region_id << " in parallel - end";
252 }
253
254 BOOST_LOG_TRIVIAL(debug) << "Generating perimeters in parallel - start";
255 tbb::parallel_for(
256 tbb::blocked_range<size_t>(0, m_layers.size()),
257 [this](const tbb::blocked_range<size_t>& range) {
258 PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
259 for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
260 m_print->throw_if_canceled();
261 m_layers[layer_idx]->make_perimeters();
262 }
263 }
264 );
266 BOOST_LOG_TRIVIAL(debug) << "Generating perimeters in parallel - end";
267
268 this->set_done(posPerimeters);
269}
void slice()
Definition PrintObjectSlice.cpp:496
bool m_typed_slices
Definition Print.hpp:415

References _u8L, Slic3r::PrintRegion::config(), Slic3r::log_memory_info(), m_layers, Slic3r::PrintObjectBaseWithState< Print, PrintObjectStep, posCount >::m_print, m_typed_slices, num_printing_regions(), Slic3r::posPerimeters, printing_region(), Slic3r::range(), Slic3r::PrintObjectBaseWithState< Print, PrintObjectStep, posCount >::set_started(), Slic3r::PrintBase::set_status(), slice(), and Slic3r::PrintBase::throw_if_canceled().

+ Here is the call graph for this function:

◆ model_object() [1/2]

ModelObject * Slic3r::PrintObjectBase::model_object ( )
inlineinherited
363{ return m_model_object; }
ModelObject * m_model_object
Definition PrintBase.hpp:376

References Slic3r::PrintObjectBase::m_model_object.

◆ model_object() [2/2]

◆ num_printing_regions()

size_t Slic3r::PrintObject::num_printing_regions ( ) const
throw (
)
inline
312{ return m_shared_regions->all_regions.size(); }

References Slic3r::PrintObjectRegions::all_regions, and m_shared_regions.

Referenced by Slic3r::FFFTreeSupport::TreeSupportMeshGroupSettings::TreeSupportMeshGroupSettings(), Slic3r::FillAdaptive::adaptive_fill_line_spacing(), make_perimeters(), and Slic3r::mmu_segmentation_top_and_bottom_layers().

+ Here is the caller graph for this function:

◆ object_config_from_model_object()

PrintObjectConfig Slic3r::PrintObject::object_config_from_model_object ( const PrintObjectConfig default_object_config,
const ModelObject object,
size_t  num_extruders 
)
staticprivate
2463{
2464 PrintObjectConfig config = default_object_config;
2465 {
2466 DynamicPrintConfig src_normalized(object.config.get());
2467 src_normalized.normalize_fdm();
2468 config.apply(src_normalized, true);
2469 }
2470 // Clamp invalid extruders to the default extruder (with index 1).
2471 clamp_exturder_to_default(config.support_material_extruder, num_extruders);
2472 clamp_exturder_to_default(config.support_material_interface_extruder, num_extruders);
2473 return config;
2474}
PrintObjectConfig
Definition PrintConfig.hpp:840
static void clamp_exturder_to_default(ConfigOptionInt &opt, size_t num_extruders)
Definition PrintObject.cpp:2455

References Slic3r::clamp_exturder_to_default(), Slic3r::DynamicPrintConfig::normalize_fdm(), and Slic3r::PrintObjectConfig.

+ Here is the call graph for this function:

◆ object_extruders()

std::vector< unsigned int > Slic3r::PrintObject::object_extruders ( ) const
2583{
2584 std::vector<unsigned int> extruders;
2585 extruders.reserve(this->all_regions().size() * 3);
2586 for (const PrintRegion &region : this->all_regions())
2587 region.collect_object_printing_extruders(*this->print(), extruders);
2588 sort_remove_duplicates(extruders);
2589 return extruders;
2590}

References Slic3r::sort_remove_duplicates().

Referenced by Slic3r::get_default_perimeter_spacing().

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

◆ prepare_adaptive_infill_data()

std::pair< FillAdaptive::OctreePtr, FillAdaptive::OctreePtr > Slic3r::PrintObject::prepare_adaptive_infill_data ( const std::vector< std::pair< const Surface *, float > > &  surfaces_w_bottom_z) const
private
538{
539 using namespace FillAdaptive;
540
541 auto [adaptive_line_spacing, support_line_spacing] = adaptive_fill_line_spacing(*this);
542 if ((adaptive_line_spacing == 0. && support_line_spacing == 0.) || this->layers().empty())
543 return std::make_pair(OctreePtr(), OctreePtr());
544
546 // Rotate mesh and build octree on it with axis-aligned (standart base) cubes.
547 auto to_octree = transform_to_octree().toRotationMatrix();
548 its_transform(mesh, to_octree * this->trafo_centered(), true);
549
550 // Triangulate internal bridging surfaces.
551 std::vector<std::vector<Vec3d>> overhangs(std::max(surfaces_w_bottom_z.size(), size_t(1)));
552 // ^ make sure vector is not empty, even with no briding surfaces we still want to build the adaptive trees later, some continue normally
553 tbb::parallel_for(tbb::blocked_range<int>(0, surfaces_w_bottom_z.size()),
554 [this, &to_octree, &overhangs, &surfaces_w_bottom_z](const tbb::blocked_range<int> &range) {
555 PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
556 for (int surface_idx = range.begin(); surface_idx < range.end(); ++surface_idx) {
557 std::vector<Vec3d> &out = overhangs[surface_idx];
558 m_print->throw_if_canceled();
559 append(out, triangulate_expolygon_3d(surfaces_w_bottom_z[surface_idx].first->expolygon,
560 surfaces_w_bottom_z[surface_idx].second));
561 for (Vec3d &p : out)
562 p = (to_octree * p).eval();
563 }
564 });
565 // and gather them.
566 for (size_t i = 1; i < overhangs.size(); ++ i)
567 append(overhangs.front(), std::move(overhangs[i]));
568
569 return std::make_pair(
570 adaptive_line_spacing ? build_octree(mesh, overhangs.front(), adaptive_line_spacing, false) : OctreePtr(),
571 support_line_spacing ? build_octree(mesh, overhangs.front(), support_line_spacing, true) : OctreePtr());
572}
indexed_triangle_set raw_indexed_triangle_set() const
Definition Model.cpp:972
EIGEN_DEVICE_FUNC Matrix3 toRotationMatrix() const
Definition Quaternion.h:536
std::unique_ptr< Octree, OctreeDeleter > OctreePtr
Definition FillAdaptive.hpp:28
Eigen::Quaterniond transform_to_octree()
Definition FillAdaptive.cpp:407
std::pair< double, double > adaptive_fill_line_spacing(const PrintObject &print_object)
Definition FillAdaptive.cpp:276
OctreePtr build_octree(const indexed_triangle_set &triangle_mesh, const std::vector< Vec3d > &overhang_triangles, coordf_t line_spacing, bool support_overhangs_only)
Definition FillAdaptive.cpp:1465
TPoint< P > front(const P &p)
Definition geometry_traits.hpp:872
void its_transform(indexed_triangle_set &its, T *trafo3x4)
Definition stl.h:266
Definition stl.h:157

References Slic3r::empty(), its_transform(), Slic3r::range(), and Eigen::QuaternionBase< Derived >::toRotationMatrix().

+ Here is the call graph for this function:

◆ prepare_infill()

void Slic3r::PrintObject::prepare_infill ( )
private
272{
273 if (! this->set_started(posPrepareInfill))
274 return;
275
276 m_print->set_status(30, _u8L("Preparing infill"));
277
278 if (m_typed_slices) {
279 // To improve robustness of detect_surfaces_type() when reslicing (working with typed slices), see GH issue #7442.
280 // The preceding step (perimeter generator) only modifies extra_perimeters and the extra perimeters are only used by discover_vertical_shells()
281 // with more than a single region. If this step does not use Surface::extra_perimeters or Surface::extra_perimeters is always zero, it is safe
282 // to reset to the untyped slices before re-runnning detect_surfaces_type().
283 for (Layer* layer : m_layers) {
284 layer->restore_untyped_slices_no_extra_perimeters();
286 }
287 }
288
289 // This will assign a type (top/bottom/internal) to $layerm->slices.
290 // Then the classifcation of $layerm->slices is transfered onto
291 // the $layerm->fill_surfaces by clipping $layerm->fill_surfaces
292 // by the cummulative area of the previous $layerm->fill_surfaces.
293 this->detect_surfaces_type();
295
296 // Decide what surfaces are to be filled.
297 // Here the stTop / stBottomBridge / stBottom infill is turned to just stInternal if zero top / bottom infill layers are configured.
298 // Also tiny stInternal surfaces are turned to stInternalSolid.
299 BOOST_LOG_TRIVIAL(info) << "Preparing fill surfaces..." << log_memory_info();
300 for (auto *layer : m_layers)
301 for (auto *region : layer->m_regions) {
302 region->prepare_fill_surfaces();
304 }
305
306
307 // Add solid fills to ensure the shell vertical thickness.
310
311 // Debugging output.
312#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
313 for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id) {
314 for (const Layer *layer : m_layers) {
315 LayerRegion *layerm = layer->m_regions[region_id];
316 layerm->export_region_slices_to_svg_debug("3_discover_vertical_shells-final");
317 layerm->export_region_fill_surfaces_to_svg_debug("3_discover_vertical_shells-final");
318 } // for each layer
319 } // for each region
320#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
321
322 // this will detect bridges and reverse bridges
323 // and rearrange top/bottom/internal surfaces
324 // It produces enlarged overlapping bridging areas.
325 //
326 // 1) stBottomBridge / stBottom infill is grown by 3mm and clipped by the total infill area. Bridges are detected. The areas may overlap.
327 // 2) stTop is grown by 3mm and clipped by the grown bottom areas. The areas may overlap.
328 // 3) Clip the internal surfaces by the grown top/bottom surfaces.
329 // 4) Merge surfaces with the same style. This will mostly get rid of the overlaps.
330 //FIXME This does not likely merge surfaces, which are supported by a material with different colors, but same properties.
333
334 // Debugging output.
335#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
336 for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id) {
337 for (const Layer *layer : m_layers) {
338 LayerRegion *layerm = layer->m_regions[region_id];
339 layerm->export_region_slices_to_svg_debug("3_process_external_surfaces-final");
340 layerm->export_region_fill_surfaces_to_svg_debug("3_process_external_surfaces-final");
341 } // for each layer
342 } // for each region
343#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
344
345 // Detect, which fill surfaces are near external layers.
346 // They will be split in internal and internal-solid surfaces.
347 // The purpose is to add a configurable number of solid layers to support the TOP surfaces
348 // and to add a configurable number of solid layers above the BOTTOM / BOTTOMBRIDGE surfaces
349 // to close these surfaces reliably.
350 //FIXME Vojtech: Is this a good place to add supporting infills below sloping perimeters?
353
354#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
355 for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id) {
356 for (const Layer *layer : m_layers) {
357 LayerRegion *layerm = layer->m_regions[region_id];
358 layerm->export_region_slices_to_svg_debug("7_discover_horizontal_shells-final");
359 layerm->export_region_fill_surfaces_to_svg_debug("7_discover_horizontal_shells-final");
360 } // for each layer
361 } // for each region
362#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
363
364 // Only active if config->infill_only_where_needed. This step trims the sparse infill,
365 // so it acts as an internal support. It maintains all other infill types intact.
366 // Here the internal surfaces and perimeters have to be supported by the sparse infill.
367 //FIXME The surfaces are supported by a sparse infill, but the sparse infill is only as large as the area to support.
368 // Likely the sparse infill will not be anchored correctly, so it will not work as intended.
369 // Also one wishes the perimeters to be supported by a full infill.
370 // this->clip_fill_surfaces();
371 // m_print->throw_if_canceled();
372
373#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
374 for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id) {
375 for (const Layer *layer : m_layers) {
376 LayerRegion *layerm = layer->m_regions[region_id];
377 layerm->export_region_slices_to_svg_debug("8_clip_surfaces-final");
378 layerm->export_region_fill_surfaces_to_svg_debug("8_clip_surfaces-final");
379 } // for each layer
380 } // for each region
381#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
382
383 // the following step needs to be done before combination because it may need
384 // to remove only half of the combined infill
385 this->bridge_over_infill();
387
388 // combine fill surfaces to honor the "infill every N layers" option
389 this->combine_infill();
391
392#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
393 for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id) {
394 for (const Layer *layer : m_layers) {
395 LayerRegion *layerm = layer->m_regions[region_id];
396 layerm->export_region_slices_to_svg_debug("9_prepare_infill-final");
397 layerm->export_region_fill_surfaces_to_svg_debug("9_prepare_infill-final");
398 } // for each layer
399 } // for each region
400 for (const Layer *layer : m_layers) {
401 layer->export_region_slices_to_svg_debug("9_prepare_infill-final");
402 layer->export_region_fill_surfaces_to_svg_debug("9_prepare_infill-final");
403 } // for each layer
404#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
405
407}
void discover_vertical_shells()
Definition PrintObject.cpp:1197
void combine_infill()
Definition PrintObject.cpp:2760
void detect_surfaces_type()
Definition PrintObject.cpp:903
void process_external_surfaces()
Definition PrintObject.cpp:1104
void discover_horizontal_shells()
Definition PrintObject.cpp:2723
void bridge_over_infill()
Definition PrintObject.cpp:1629

References _u8L, Slic3r::LayerRegion::export_region_fill_surfaces_to_svg_debug(), Slic3r::LayerRegion::export_region_slices_to_svg_debug(), Slic3r::log_memory_info(), and Slic3r::posPrepareInfill.

+ Here is the call graph for this function:

◆ prepare_lightning_infill_data()

FillLightning::GeneratorPtr Slic3r::PrintObject::prepare_lightning_infill_data ( )
private
575{
576 bool has_lightning_infill = false;
577 coordf_t lightning_density = 0.;
578 size_t lightning_cnt = 0;
579 for (size_t region_id = 0; region_id < this->num_printing_regions(); ++region_id)
580 if (const PrintRegionConfig &config = this->printing_region(region_id).config(); config.fill_density > 0 && config.fill_pattern == ipLightning) {
581 has_lightning_infill = true;
582 lightning_density += config.fill_density;
583 ++lightning_cnt;
584 }
585
586 if (has_lightning_infill)
587 lightning_density /= coordf_t(lightning_cnt);
588
589 return has_lightning_infill ? FillLightning::build_generator(std::as_const(*this), lightning_density, [this]() -> void { this->throw_if_canceled(); }) : FillLightning::GeneratorPtr();
590}
GeneratorPtr build_generator(const PrintObject &print_object, const coordf_t fill_density, const std::function< void()> &throw_on_cancel_callback)
Definition FillLightning.cpp:29
std::unique_ptr< Generator, GeneratorDeleter > GeneratorPtr
Definition FillLightning.hpp:15
double coordf_t
Definition GUI_ObjectList.hpp:36

References Slic3r::ipLightning, and Slic3r::PrintRegionConfig.

◆ print() [1/2]

Print * Slic3r::PrintObjectBaseWithState< Print , PrintObjectStep , COUNT >::print ( )
inlineinherited
735{ return m_print; }

◆ print() [2/2]

const Print * Slic3r::PrintObjectBaseWithState< Print , PrintObjectStep , COUNT >::print ( ) const
inlineinherited
736{ return m_print; }

◆ printing_region()

const PrintRegion & Slic3r::PrintObject::printing_region ( size_t  idx) const
throw (
)
inline
313{ return *m_shared_regions->all_regions[idx].get(); }

References Slic3r::PrintObjectRegions::all_regions, and m_shared_regions.

Referenced by Slic3r::FFFTreeSupport::TreeSupportMeshGroupSettings::TreeSupportMeshGroupSettings(), Slic3r::FillAdaptive::adaptive_fill_line_spacing(), make_perimeters(), and Slic3r::mmu_segmentation_top_and_bottom_layers().

+ Here is the caller graph for this function:

◆ process_external_surfaces()

void Slic3r::PrintObject::process_external_surfaces ( )
private
1105{
1106 BOOST_LOG_TRIVIAL(info) << "Processing external surfaces..." << log_memory_info();
1107
1108 // Cached surfaces covered by some extrusion, defining regions, over which the from the surfaces one layer higher are allowed to expand.
1109 std::vector<Polygons> surfaces_covered;
1110 // Is there any printing region, that has zero infill? If so, then we don't want the expansion to be performed over the complete voids, but only
1111 // over voids, which are supported by the layer below.
1112 bool has_voids = false;
1113 for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id)
1114 if (this->printing_region(region_id).config().fill_density == 0) {
1115 has_voids = true;
1116 break;
1117 }
1118 if (has_voids && m_layers.size() > 1) {
1119 // All but stInternal fill surfaces will get expanded and possibly trimmed.
1120 std::vector<unsigned char> layer_expansions_and_voids(m_layers.size(), false);
1121 for (size_t layer_idx = 1; layer_idx < m_layers.size(); ++ layer_idx) {
1122 const Layer *layer = m_layers[layer_idx];
1123 bool expansions = false;
1124 bool voids = false;
1125 for (const LayerRegion *layerm : layer->regions()) {
1126 for (const Surface &surface : layerm->fill_surfaces()) {
1127 if (surface.surface_type == stInternal)
1128 voids = true;
1129 else
1130 expansions = true;
1131 if (voids && expansions) {
1132 layer_expansions_and_voids[layer_idx] = true;
1133 goto end;
1134 }
1135 }
1136 }
1137 end:;
1138 }
1139 BOOST_LOG_TRIVIAL(debug) << "Collecting surfaces covered with extrusions in parallel - start";
1140 surfaces_covered.resize(m_layers.size() - 1, Polygons());
1141 auto unsupported_width = - float(scale_(0.3 * EXTERNAL_INFILL_MARGIN));
1142 tbb::parallel_for(
1143 tbb::blocked_range<size_t>(0, m_layers.size() - 1),
1144 [this, &surfaces_covered, &layer_expansions_and_voids, unsupported_width](const tbb::blocked_range<size_t>& range) {
1145 PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
1146 for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx)
1147 if (layer_expansions_and_voids[layer_idx + 1]) {
1148 // Layer above is partially filled with solid infill (top, bottom, bridging...),
1149 // while some sparse inill regions are empty (0% infill).
1150 m_print->throw_if_canceled();
1151 Polygons voids;
1152 for (const LayerRegion *layerm : m_layers[layer_idx]->regions()) {
1153 if (layerm->region().config().fill_density.value == 0.)
1154 for (const Surface &surface : layerm->fill_surfaces())
1155 // Shrink the holes, let the layer above expand slightly inside the unsupported areas.
1156 polygons_append(voids, offset(surface.expolygon, unsupported_width));
1157 }
1158 surfaces_covered[layer_idx] = diff(m_layers[layer_idx]->lslices, voids);
1159 }
1160 }
1161 );
1163 BOOST_LOG_TRIVIAL(debug) << "Collecting surfaces covered with extrusions in parallel - end";
1164 }
1165
1166 for (size_t region_id = 0; region_id < this->num_printing_regions(); ++region_id) {
1167 BOOST_LOG_TRIVIAL(debug) << "Processing external surfaces for region " << region_id << " in parallel - start";
1168 tbb::parallel_for(
1169 tbb::blocked_range<size_t>(0, m_layers.size()),
1170 [this, &surfaces_covered, region_id](const tbb::blocked_range<size_t>& range) {
1171 PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
1172 for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
1173 m_print->throw_if_canceled();
1174 // BOOST_LOG_TRIVIAL(trace) << "Processing external surface, layer" << m_layers[layer_idx]->print_z;
1175 m_layers[layer_idx]->get_region(int(region_id))->process_external_surfaces(
1176 // lower layer
1177 (layer_idx == 0) ? nullptr : m_layers[layer_idx - 1],
1178 // lower layer polygons with density > 0%
1179 (layer_idx == 0 || surfaces_covered.empty() || surfaces_covered[layer_idx - 1].empty()) ? nullptr : &surfaces_covered[layer_idx - 1]);
1180 }
1181 }
1182 );
1184 BOOST_LOG_TRIVIAL(debug) << "Processing external surfaces for region " << region_id << " in parallel - end";
1185 }
1186
1187 if (this->has_raft() && ! m_layers.empty()) {
1188 // Adjust bridge direction of 1st object layer over raft to be perpendicular to the raft contact layer direction.
1189 Layer &layer = *m_layers.front();
1190 assert(layer.id() > 0);
1191 for (LayerRegion *layerm : layer.regions())
1192 for (Surface &fill : layerm->m_fill_surfaces)
1193 fill.bridge_angle = -1;
1194 }
1195} // void PrintObject::process_external_surfaces()
static constexpr double EXTERNAL_INFILL_MARGIN
Definition libslic3r.h:66

References EXTERNAL_INFILL_MARGIN, Slic3r::log_memory_info(), Slic3r::range(), Slic3r::Layer::regions(), scale_, and Slic3r::stInternal.

+ Here is the call graph for this function:

◆ project_and_append_custom_facets()

void Slic3r::PrintObject::project_and_append_custom_facets ( bool  seam,
EnforcerBlockerType  type,
std::vector< Polygons > &  expolys 
) const
3068{
3069 for (const ModelVolume* mv : this->model_object()->volumes)
3070 if (mv->is_model_part()) {
3071 const indexed_triangle_set custom_facets = seam
3072 ? mv->seam_facets.get_facets_strict(*mv, type)
3073 : mv->supported_facets.get_facets_strict(*mv, type);
3074 if (! custom_facets.indices.empty()) {
3075 if (seam)
3076 project_triangles_to_slabs(this->layers(), custom_facets,
3077 (this->trafo_centered() * mv->get_matrix()).cast<float>(),
3078 seam, out);
3079 else {
3080 std::vector<Polygons> projected;
3081 // Support blockers or enforcers. Project downward facing painted areas upwards to their respective slicing plane.
3082 slice_mesh_slabs(custom_facets, zs_from_layers(this->layers()), this->trafo_centered() * mv->get_matrix(), nullptr, &projected, [](){});
3083 // Merge these projections with the output, layer by layer.
3084 assert(! projected.empty());
3085 assert(out.empty() || out.size() == projected.size());
3086 if (out.empty())
3087 out = std::move(projected);
3088 else
3089 for (size_t i = 0; i < out.size(); ++ i)
3090 append(out[i], std::move(projected[i]));
3091 }
3092 }
3093 }
3094}
void slice_mesh_slabs(const indexed_triangle_set &mesh, const std::vector< float > &zs, const Transform3d &trafo, std::vector< Polygons > *out_top, std::vector< Polygons > *out_bottom, std::function< void()> throw_on_cancel)
Definition TriangleMeshSlicer.cpp:1993
std::vector< float > zs_from_layers(const LayerContainer &layers)
Definition Layer.hpp:458
static void project_triangles_to_slabs(SpanOfConstPtrs< Layer > layers, const indexed_triangle_set &custom_facets, const Transform3f &tr, bool seam, std::vector< Polygons > &out)
Definition PrintObject.cpp:2879
std::vector< stl_triangle_vertex_indices > indices
Definition stl.h:164

References indexed_triangle_set::indices, Slic3r::project_triangles_to_slabs(), Slic3r::slice_mesh_slabs(), and Slic3r::zs_from_layers().

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

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

◆ query_reset_dirty_step_unguarded()

bool Slic3r::PrintObjectBaseWithState< Print , PrintObjectStep , COUNT >::query_reset_dirty_step_unguarded ( PrintObjectStepEnum  step)
inlineprotectedinherited
790{ return m_state.query_reset_dirty_unguarded(step); }
bool query_reset_dirty_unguarded(StepType step)
Definition PrintBase.hpp:297

◆ serialize()

template<class Archive >
void Slic3r::ObjectBase::serialize ( Archive &  ar)
inlineprivateinherited
92{ ar(m_id); }

References Slic3r::ObjectBase::m_id.

◆ set_done()

PrintStateBase::TimeStamp Slic3r::PrintObjectBaseWithState< Print , PrintObjectStep , COUNT >::set_done ( PrintObjectStepEnum  step)
inlineprotectedinherited
763 {
764 std::pair<PrintStateBase::TimeStamp, bool> status = m_state.set_done(step, PrintObjectBase::state_mutex(m_print), [this](){ this->throw_if_canceled(); });
765 if (status.second)
766 this->status_update_warnings(m_print, static_cast<int>(step), PrintStateBase::WarningLevel::NON_CRITICAL, std::string());
767 return status.first;
768 }
std::pair< TimeStamp, bool > set_done(StepType step, std::mutex &mtx, ThrowIfCanceled throw_if_canceled)
Definition PrintBase.hpp:202

◆ set_instances()

PrintBase::ApplyStatus Slic3r::PrintObject::set_instances ( PrintInstances &&  instances)
private
128{
129 for (PrintInstance &i : instances)
130 // Add the center offset, which will be subtracted from the mesh when slicing.
131 i.shift += m_center_offset;
132 // Invalidate and set copies.
134 bool equal_length = instances.size() == m_instances.size();
135 bool equal = equal_length && std::equal(instances.begin(), instances.end(), m_instances.begin(),
136 [](const PrintInstance& lhs, const PrintInstance& rhs) { return lhs.model_instance == rhs.model_instance && lhs.shift == rhs.shift; });
137 if (! equal) {
139 if (m_print->invalidate_steps({ psSkirtBrim, psGCodeExport }) ||
140 (! equal_length && m_print->invalidate_step(psWipeTower)))
142 m_instances = std::move(instances);
143 for (PrintInstance &i : m_instances)
144 i.print_object = this;
145 }
146 return status;
147}
ApplyStatus
Definition PrintBase.hpp:423
@ APPLY_STATUS_UNCHANGED
Definition PrintBase.hpp:425
@ APPLY_STATUS_CHANGED
Definition PrintBase.hpp:428
@ APPLY_STATUS_INVALIDATED
Definition PrintBase.hpp:430

References Slic3r::PrintBase::APPLY_STATUS_CHANGED, Slic3r::PrintBase::APPLY_STATUS_INVALIDATED, Slic3r::PrintBase::APPLY_STATUS_UNCHANGED, instances(), Slic3r::Print::invalidate_step(), Slic3r::PrintBaseWithState< PrintStepEnumType, COUNT >::invalidate_steps(), m_center_offset, m_instances, Slic3r::PrintObjectBaseWithState< Print, PrintObjectStep, posCount >::m_print, and Slic3r::psWipeTower.

Referenced by PrintObject().

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

◆ set_invalid_id()

void Slic3r::ObjectBase::set_invalid_id ( )
inlineprotectedinherited
74{ m_id = 0; }

References Slic3r::ObjectBase::m_id.

Referenced by Slic3r::CutObjectBase::invalidate().

+ Here is the caller graph for this function:

◆ set_new_unique_id()

void Slic3r::ObjectBase::set_new_unique_id ( )
inlineprotectedinherited
73{ m_id = generate_new_id(); }
static ObjectID generate_new_id()
Definition ObjectID.hpp:84

References Slic3r::ObjectBase::generate_new_id(), and Slic3r::ObjectBase::m_id.

Referenced by Slic3r::ModelVolume::ModelVolume(), Slic3r::Model::assign_new_unique_ids_recursive(), Slic3r::ObjectBase::assign_new_unique_ids_recursive(), Slic3r::ModelObject::assign_new_unique_ids_recursive(), Slic3r::CutObjectBase::init(), Slic3r::ModelMaterial::set_new_unique_id(), Slic3r::ModelObject::set_new_unique_id(), and Slic3r::ModelVolume::set_new_unique_id().

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

◆ set_started()

bool Slic3r::PrintObjectBaseWithState< Print , PrintObjectStep , COUNT >::set_started ( PrintObjectStepEnum  step)
inlineprotectedinherited
762 { return m_state.set_started(step, PrintObjectBase::state_mutex(m_print), [this](){ this->throw_if_canceled(); }); }
bool set_started(StepType step, std::mutex &mtx, ThrowIfCanceled throw_if_canceled)
Definition PrintBase.hpp:169

◆ shared_regions()

const PrintObjectRegions * Slic3r::PrintObject::shared_regions ( ) const
throw (
)
inline
316{ return m_shared_regions; }

References m_shared_regions.

Referenced by Slic3r::FillLightning::Generator::Generator().

+ Here is the caller graph for this function:

◆ size()

const Vec3crd & Slic3r::PrintObject::size ( ) const
inline
245{ return m_size; }

References m_size.

Referenced by Slic3r::SupportSpotsGenerator::SupportGridFilter::SupportGridFilter().

+ Here is the caller graph for this function:

◆ slice()

void Slic3r::PrintObject::slice ( )
497{
498 if (! this->set_started(posSlice))
499 return;
500 m_print->set_status(10, _u8L("Processing triangulated mesh"));
501 std::vector<coordf_t> layer_height_profile;
502 this->update_layer_height_profile(*this->model_object(), m_slicing_params, layer_height_profile);
504 m_typed_slices = false;
505 this->clear_layers();
506 m_layers = new_layers(this, generate_object_layers(m_slicing_params, layer_height_profile));
507 this->slice_volumes();
509#if 0
510 // Layer::slicing_errors is no more set since 1.41.1 or possibly earlier, thus this code
511 // was not really functional for a long day and nobody missed it.
512 // Could we reuse this fixing code one day?
513
514 // Fix the model.
515 //FIXME is this the right place to do? It is done repeateadly at the UI and now here at the backend.
516 std::string warning = fix_slicing_errors(m_layers, [this](){ m_print->throw_if_canceled(); });
518 if (! warning.empty())
519 BOOST_LOG_TRIVIAL(info) << warning;
520#endif
521 // Update bounding boxes, back up raw slices of complex models.
522 tbb::parallel_for(
523 tbb::blocked_range<size_t>(0, m_layers.size()),
524 [this](const tbb::blocked_range<size_t> &range) {
525 for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
526 m_print->throw_if_canceled();
527 Layer &layer = *m_layers[layer_idx];
528 layer.lslices_ex.clear();
529 layer.lslices_ex.reserve(layer.lslices.size());
530 for (const ExPolygon &expoly : layer.lslices)
531 layer.lslices_ex.push_back({ get_extents(expoly) });
532 layer.backup_untyped_slices();
533 }
534 });
535 // Interlink the lslices into a Z graph.
536 tbb::parallel_for(
537 tbb::blocked_range<size_t>(1, m_layers.size()),
538 [this](const tbb::blocked_range<size_t> &range) {
539 for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
540 m_print->throw_if_canceled();
541 Layer::build_up_down_graph(*m_layers[layer_idx - 1], *m_layers[layer_idx]);
542 }
543 });
544 if (m_layers.empty())
545 throw Slic3r::SlicingError("No layers were detected. You might want to repair your STL file(s) or check their size or thickness and retry.\n");
546 this->set_done(posSlice);
547}
static bool update_layer_height_profile(const ModelObject &model_object, const SlicingParameters &slicing_parameters, std::vector< coordf_t > &layer_height_profile)
Definition PrintObject.cpp:2592
void slice_volumes()
Definition PrintObjectSlice.cpp:684
LayerPtrs new_layers(PrintObject *print_object, const std::vector< coordf_t > &object_layers)
Definition PrintObjectSlice.cpp:16
std::vector< coordf_t > generate_object_layers(const SlicingParameters &slicing_params, const std::vector< coordf_t > &layer_height_profile)
Definition Slicing.cpp:595

References _u8L, Slic3r::generate_object_layers(), Slic3r::new_layers(), Slic3r::posSlice, and Slic3r::range().

Referenced by make_perimeters().

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

◆ slice_support_blockers()

std::vector< Polygons > Slic3r::PrintObject::slice_support_blockers ( ) const
inline
std::vector< Polygons > slice_support_volumes(const ModelVolumeType model_volume_type) const
Definition PrintObjectSlice.cpp:825

References slice_support_volumes(), and Slic3r::SUPPORT_BLOCKER.

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

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

◆ slice_support_enforcers()

std::vector< Polygons > Slic3r::PrintObject::slice_support_enforcers ( ) const
inline

References slice_support_volumes(), and Slic3r::SUPPORT_ENFORCER.

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

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

◆ slice_support_volumes()

std::vector< Polygons > Slic3r::PrintObject::slice_support_volumes ( const ModelVolumeType  model_volume_type) const
826{
827 auto it_volume = this->model_object()->volumes.begin();
828 auto it_volume_end = this->model_object()->volumes.end();
829 for (; it_volume != it_volume_end && (*it_volume)->type() != model_volume_type; ++ it_volume) ;
830 std::vector<Polygons> slices;
831 if (it_volume != it_volume_end) {
832 // Found at least a single support volume of model_volume_type.
833 std::vector<float> zs = zs_from_layers(this->layers());
834 std::vector<char> merge_layers;
835 bool merge = false;
836 const Print *print = this->print();
837 auto throw_on_cancel_callback = std::function<void()>([print](){ print->throw_if_canceled(); });
838 MeshSlicingParamsEx params;
839 params.trafo = this->trafo_centered();
840 for (; it_volume != it_volume_end; ++ it_volume)
841 if ((*it_volume)->type() == model_volume_type) {
842 std::vector<ExPolygons> slices2 = slice_volume(*(*it_volume), zs, params, throw_on_cancel_callback);
843 if (slices.empty()) {
844 slices.reserve(slices2.size());
845 for (ExPolygons &src : slices2)
846 slices.emplace_back(to_polygons(std::move(src)));
847 } else if (!slices2.empty()) {
848 if (merge_layers.empty())
849 merge_layers.assign(zs.size(), false);
850 for (size_t i = 0; i < zs.size(); ++ i) {
851 if (slices[i].empty())
852 slices[i] = to_polygons(std::move(slices2[i]));
853 else if (! slices2[i].empty()) {
854 append(slices[i], to_polygons(std::move(slices2[i])));
855 merge_layers[i] = true;
856 merge = true;
857 }
858 }
859 }
860 }
861 if (merge) {
862 std::vector<Polygons*> to_merge;
863 to_merge.reserve(zs.size());
864 for (size_t i = 0; i < zs.size(); ++ i)
865 if (merge_layers[i])
866 to_merge.emplace_back(&slices[i]);
867 tbb::parallel_for(
868 tbb::blocked_range<size_t>(0, to_merge.size()),
869 [&to_merge](const tbb::blocked_range<size_t> &range) {
870 for (size_t i = range.begin(); i < range.end(); ++ i)
871 *to_merge[i] = union_(*to_merge[i]);
872 });
873 }
874 }
875 return slices;
876}
ModelVolumePtrs volumes
Definition Model.hpp:337
friend class Print
Definition Print.hpp:340
static std::vector< ExPolygons > slice_volume(const ModelVolume &volume, const std::vector< float > &zs, const MeshSlicingParamsEx &params, const std::function< void()> &throw_on_cancel_callback)
Definition PrintObjectSlice.cpp:42
TMultiShape< PolygonImpl > merge(const TMultiShape< PolygonImpl > &shapes)
Definition geometries.hpp:259

References Slic3r::empty(), Slic3r::range(), Slic3r::slice_volume(), Slic3r::PrintBase::throw_if_canceled(), Slic3r::to_polygons(), Slic3r::MeshSlicingParams::trafo, and Slic3r::zs_from_layers().

Referenced by slice_support_blockers(), and slice_support_enforcers().

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

◆ slice_volumes()

void Slic3r::PrintObject::slice_volumes ( )
private
685{
686 BOOST_LOG_TRIVIAL(info) << "Slicing volumes..." << log_memory_info();
687 const Print *print = this->print();
688 const auto throw_on_cancel_callback = std::function<void()>([print](){ print->throw_if_canceled(); });
689
690 // Clear old LayerRegions, allocate for new PrintRegions.
691 for (Layer* layer : m_layers) {
692 layer->m_regions.clear();
693 layer->m_regions.reserve(m_shared_regions->all_regions.size());
694 for (const std::unique_ptr<PrintRegion> &pr : m_shared_regions->all_regions)
695 layer->m_regions.emplace_back(new LayerRegion(layer, pr.get()));
696 }
697
698 std::vector<float> slice_zs = zs_from_layers(m_layers);
699 std::vector<std::vector<ExPolygons>> region_slices = slices_to_regions(this->model_object()->volumes, *m_shared_regions, slice_zs,
701 print->config(), this->config(), this->trafo_centered(),
702 this->model_object()->volumes, m_shared_regions->layer_ranges, slice_zs, throw_on_cancel_callback),
703 throw_on_cancel_callback);
704
705 for (size_t region_id = 0; region_id < region_slices.size(); ++ region_id) {
706 std::vector<ExPolygons> &by_layer = region_slices[region_id];
707 for (size_t layer_id = 0; layer_id < by_layer.size(); ++ layer_id)
708 m_layers[layer_id]->regions()[region_id]->m_slices.append(std::move(by_layer[layer_id]), stInternal);
709 }
710 region_slices.clear();
711
712 BOOST_LOG_TRIVIAL(debug) << "Slicing volumes - removing top empty layers";
713 while (! m_layers.empty()) {
714 const Layer *layer = m_layers.back();
715 if (! layer->empty())
716 break;
717 delete layer;
718 m_layers.pop_back();
719 }
720 if (! m_layers.empty())
721 m_layers.back()->upper_layer = nullptr;
723
724 // Is any ModelVolume MMU painted?
725 if (const auto& volumes = this->model_object()->volumes;
726 m_print->config().nozzle_diameter.size() > 1 &&
727 std::find_if(volumes.begin(), volumes.end(), [](const ModelVolume* v) { return !v->mmu_segmentation_facets.empty(); }) != volumes.end()) {
728
729 // If XY Size compensation is also enabled, notify the user that XY Size compensation
730 // would not be used because the object is multi-material painted.
731 if (m_config.xy_size_compensation.value != 0.f) {
734 _u8L("An object has enabled XY Size compensation which will not be used because it is also multi-material painted.\nXY Size "
735 "compensation cannot be combined with multi-material painting.") +
736 "\n" + (_u8L("Object name")) + ": " + this->model_object()->name);
737 }
738
739 BOOST_LOG_TRIVIAL(debug) << "Slicing volumes - MMU segmentation";
741 }
742
743
744 BOOST_LOG_TRIVIAL(debug) << "Slicing volumes - make_slices in parallel - begin";
745 {
746 // Compensation value, scaled. Only applying the negative scaling here, as the positive scaling has already been applied during slicing.
747 const size_t num_extruders = print->config().nozzle_diameter.size();
748 const auto xy_compensation_scaled = (num_extruders > 1 && this->is_mm_painted()) ? scaled<float>(0.f) : scaled<float>(std::min(m_config.xy_size_compensation.value, 0.));
749 const float elephant_foot_compensation_scaled = (m_config.raft_layers == 0) ?
750 // Only enable Elephant foot compensation if printing directly on the print bed.
751 float(scale_(m_config.elefant_foot_compensation.value)) :
752 0.f;
753 // Uncompensated slices for the first layer in case the Elephant foot compensation is applied.
754 ExPolygons lslices_1st_layer;
755 tbb::parallel_for(
756 tbb::blocked_range<size_t>(0, m_layers.size()),
757 [this, xy_compensation_scaled, elephant_foot_compensation_scaled, &lslices_1st_layer](const tbb::blocked_range<size_t>& range) {
758 for (size_t layer_id = range.begin(); layer_id < range.end(); ++ layer_id) {
759 m_print->throw_if_canceled();
760 Layer *layer = m_layers[layer_id];
761 // Apply size compensation and perform clipping of multi-part objects.
762 float elfoot = (layer_id == 0) ? elephant_foot_compensation_scaled : 0.f;
763 if (layer->m_regions.size() == 1) {
764 // Optimized version for a single region layer.
765 // Single region, growing or shrinking.
766 LayerRegion *layerm = layer->m_regions.front();
767 if (elfoot > 0) {
768 // Apply the elephant foot compensation and store the 1st layer slices without the Elephant foot compensation applied.
769 lslices_1st_layer = to_expolygons(std::move(layerm->m_slices.surfaces));
770 float delta = xy_compensation_scaled;
771 if (delta > elfoot) {
772 delta -= elfoot;
773 elfoot = 0.f;
774 } else if (delta > 0)
775 elfoot -= delta;
776 layerm->m_slices.set(
777 union_ex(
778 Slic3r::elephant_foot_compensation(
779 (delta == 0.f) ? lslices_1st_layer : offset_ex(lslices_1st_layer, delta),
780 layerm->flow(frExternalPerimeter), unscale<double>(elfoot))),
781 stInternal);
782 if (xy_compensation_scaled < 0.f)
783 lslices_1st_layer = offset_ex(std::move(lslices_1st_layer), xy_compensation_scaled);
784 } else if (xy_compensation_scaled < 0.f) {
785 // Apply the XY compensation.
786 layerm->m_slices.set(
787 offset_ex(to_expolygons(std::move(layerm->m_slices.surfaces)), xy_compensation_scaled),
788 stInternal);
789 }
790 } else {
791 if (xy_compensation_scaled < 0.f || elfoot > 0.f) {
792 // Apply the negative XY compensation.
793 Polygons trimming;
794 static const float eps = float(scale_(m_config.slice_closing_radius.value) * 1.5);
795 if (elfoot > 0.f) {
796 lslices_1st_layer = offset_ex(layer->merged(eps), std::min(xy_compensation_scaled, 0.f) - eps);
797 trimming = to_polygons(Slic3r::elephant_foot_compensation(lslices_1st_layer,
798 layer->m_regions.front()->flow(frExternalPerimeter), unscale<double>(elfoot)));
799 } else
800 trimming = offset(layer->merged(float(SCALED_EPSILON)), xy_compensation_scaled - float(SCALED_EPSILON));
801 for (size_t region_id = 0; region_id < layer->m_regions.size(); ++ region_id)
802 layer->m_regions[region_id]->trim_surfaces(trimming);
803 }
804 }
805 // Merge all regions' slices to get islands sorted topologically, chain them by a shortest path in separate index list
806 layer->make_slices();
807 }
808 });
809 if (elephant_foot_compensation_scaled > 0.f && ! m_layers.empty()) {
810 // The Elephant foot has been compensated, therefore the 1st layer's lslices are shrank with the Elephant foot compensation value.
811 // Store the uncompensated value there.
812 //FIXME is this operation needed? MMU painting and brim now have to do work arounds to work with compensated layer, not with the uncompensated layer.
813 // There may be subtle issues removing this block such as support raft sticking too well with the first object layer.
814 Layer &layer = *m_layers.front();
815 assert(layer.id() == 0);
816 layer.lslices = std::move(lslices_1st_layer);
817 layer.lslice_indices_sorted_by_print_order = chain_expolygons(layer.lslices);
818 }
819 }
820
822 BOOST_LOG_TRIVIAL(debug) << "Slicing volumes - make_slices in parallel - end";
823}
void active_step_add_warning(PrintStateBase::WarningLevel warning_level, const std::string &message, int message_id=0)
Definition PrintBase.hpp:794
std::vector< LayerRangeRegions > layer_ranges
Definition Print.hpp:215
static std::vector< VolumeSlices > slice_volumes_inner(const PrintConfig &print_config, const PrintObjectConfig &print_object_config, const Transform3d &object_trafo, ModelVolumePtrs model_volumes, const std::vector< PrintObjectRegions::LayerRangeRegions > &layer_ranges, const std::vector< float > &zs, const std::function< void()> &throw_on_cancel_callback)
Definition PrintObjectSlice.cpp:120
void apply_mm_segmentation(PrintObject &print_object, ThrowOnCancel throw_on_cancel)
Definition PrintObjectSlice.cpp:550
std::vector< size_t > chain_expolygons(const ExPolygons &expolygons, Point *start_near)
Definition ShortestPath.cpp:1079
static std::vector< std::vector< ExPolygons > > slices_to_regions(ModelVolumePtrs model_volumes, const PrintObjectRegions &print_object_regions, const std::vector< float > &zs, std::vector< VolumeSlices > &&volume_slices, const std::function< void()> &throw_on_cancel_callback)
Definition PrintObjectSlice.cpp:234

References _u8L, Slic3r::apply_mm_segmentation(), Slic3r::chain_expolygons(), Slic3r::Print::config(), Slic3r::Layer::empty(), Slic3r::Layer::id(), Slic3r::log_memory_info(), Slic3r::Layer::lslice_indices_sorted_by_print_order, Slic3r::Layer::lslices, Slic3r::range(), scale_, Slic3r::slice_volumes_inner(), Slic3r::slices_to_regions(), Slic3r::stInternal, Slic3r::PrintBase::throw_if_canceled(), Slic3r::Layer::upper_layer, and Slic3r::zs_from_layers().

+ Here is the call graph for this function:

◆ slicing_parameters() [1/2]

◆ slicing_parameters() [2/2]

SlicingParameters Slic3r::PrintObject::slicing_parameters ( const DynamicPrintConfig full_config,
const ModelObject model_object,
float  object_max_z 
)
static
2545{
2546 PrintConfig print_config;
2547 PrintObjectConfig object_config;
2548 PrintRegionConfig default_region_config;
2549 print_config.apply(full_config, true);
2550 object_config.apply(full_config, true);
2551 default_region_config.apply(full_config, true);
2552 size_t num_extruders = print_config.nozzle_diameter.size();
2553 object_config = object_config_from_model_object(object_config, model_object, num_extruders);
2554
2555 std::vector<unsigned int> object_extruders;
2556 for (const ModelVolume* model_volume : model_object.volumes)
2557 if (model_volume->is_model_part()) {
2559 print_config,
2560 region_config_from_model_volume(default_region_config, nullptr, *model_volume, num_extruders),
2561 object_config.brim_type != btNoBrim && object_config.brim_width > 0.,
2563 for (const std::pair<const t_layer_height_range, ModelConfig> &range_and_config : model_object.layer_config_ranges)
2564 if (range_and_config.second.has("perimeter_extruder") ||
2565 range_and_config.second.has("infill_extruder") ||
2566 range_and_config.second.has("solid_infill_extruder"))
2567 PrintRegion::collect_object_printing_extruders(
2568 print_config,
2569 region_config_from_model_volume(default_region_config, &range_and_config.second.get(), *model_volume, num_extruders),
2570 object_config.brim_type != btNoBrim && object_config.brim_width > 0.,
2572 }
2574 //FIXME add painting extruders
2575
2576 if (object_max_z <= 0.f)
2577 object_max_z = (float)model_object.raw_bounding_box().size().z();
2578 return SlicingParameters::create_from_config(print_config, object_config, object_max_z, object_extruders);
2579}
PointType size() const
Definition BoundingBox.cpp:153
std::vector< unsigned int > object_extruders() const
Definition PrintObject.cpp:2582
static PrintObjectConfig object_config_from_model_object(const PrintObjectConfig &default_object_config, const ModelObject &object, size_t num_extruders)
Definition PrintObject.cpp:2462
void collect_object_printing_extruders(const Print &print, std::vector< unsigned int > &object_extruders) const
Definition PrintRegion.cpp:80
PrintRegionConfig region_config_from_model_volume(const PrintRegionConfig &default_or_parent_region_config, const DynamicPrintConfig *layer_range_config, const ModelVolume &volume, size_t num_extruders)
Definition PrintObject.cpp:2504
static SlicingParameters create_from_config(const PrintConfig &print_config, const PrintObjectConfig &object_config, coordf_t object_height, const std::vector< unsigned int > &object_extruders)
Definition Slicing.cpp:61

References Slic3r::btNoBrim, Slic3r::ModelObject::layer_config_ranges, Slic3r::PrintObjectConfig, Slic3r::PrintRegionConfig, Slic3r::ModelObject::raw_bounding_box(), Slic3r::region_config_from_model_volume(), Slic3r::BoundingBox3Base< PointType >::size(), Slic3r::sort_remove_duplicates(), and Slic3r::ModelObject::volumes.

+ Here is the call graph for this function:

◆ state_mutex()

◆ status_update_warnings()

void Slic3r::PrintObjectBase::status_update_warnings ( PrintBase print,
int  step,
PrintStateBase::WarningLevel  warning_level,
const std::string &  message 
)
protectedinherited
121{
122 print->status_update_warnings(step, warning_level, message, this);
123}

References Slic3r::PrintBase::status_update_warnings().

Referenced by Slic3r::PrintObjectBaseWithState< PrintType, PrintObjectStepEnumType, COUNT >::active_step_add_warning(), and Slic3r::PrintObjectBaseWithState< PrintType, PrintObjectStepEnumType, COUNT >::set_done().

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

◆ step_state_with_timestamp()

PrintStateBase::StateWithTimeStamp Slic3r::PrintObjectBaseWithState< Print , PrintObjectStep , COUNT >::step_state_with_timestamp ( PrintObjectStepEnum  step) const
inlineinherited
740{ return m_state.state_with_timestamp(step, PrintObjectBase::state_mutex(m_print)); }
StateWithTimeStamp state_with_timestamp(StepType step, std::mutex &mtx) const
Definition PrintBase.hpp:118

◆ step_state_with_warnings()

PrintStateBase::StateWithWarnings Slic3r::PrintObjectBaseWithState< Print , PrintObjectStep , COUNT >::step_state_with_warnings ( PrintObjectStepEnum  step) const
inlineinherited
741{ return m_state.state_with_warnings(step, PrintObjectBase::state_mutex(m_print)); }
StateWithWarnings state_with_warnings(StepType step, std::mutex &mtx) const
Definition PrintBase.hpp:124

◆ support_layer_count()

size_t Slic3r::PrintObject::support_layer_count ( ) const
inline
294{ return m_support_layers.size(); }

References m_support_layers.

Referenced by total_layer_count().

+ Here is the caller graph for this function:

◆ support_layers() [1/2]

SupportLayerPtrs & Slic3r::PrintObject::support_layers ( )
inline
257{ return m_support_layers; }

References m_support_layers.

◆ support_layers() [2/2]

auto Slic3r::PrintObject::support_layers ( ) const
inline
248{ return SpanOfConstPtrs<SupportLayer>(const_cast<const SupportLayer* const* const>(m_support_layers.data()), m_support_layers.size()); }

References const, and m_support_layers.

Referenced by Slic3r::GUI::GLCanvas3D::_load_print_object_toolpaths(), Slic3r::GUI::GLCanvas3D::_load_print_toolpaths(), and Slic3r::getAllLayersExtrusionPathsFromObject().

+ Here is the caller graph for this function:

◆ throw_if_canceled()

void Slic3r::PrintObjectBaseWithState< Print , PrintObjectStep , COUNT >::throw_if_canceled ( )
inlineprotectedinherited
803{ if (m_print->canceled()) throw CanceledException(); }
bool canceled() const
Definition PrintBase.hpp:513

◆ timestamp()

virtual Timestamp Slic3r::ObjectBase::timestamp ( ) const
inlinevirtualinherited

Reimplemented in Slic3r::ModelConfigObject, and Slic3r::ObjectWithTimestamp.

60{ return 0; }

Referenced by Slic3r::GUI::Plater::priv::undo_redo_to().

+ Here is the caller graph for this function:

◆ total_layer_count()

size_t Slic3r::PrintObject::total_layer_count ( ) const
inline
277{ return this->layer_count() + this->support_layer_count(); }
size_t support_layer_count() const
Definition Print.hpp:294

References layer_count(), and support_layer_count().

+ Here is the call graph for this function:

◆ trafo()

const Transform3d & Slic3r::PrintObject::trafo ( ) const
inline
249{ return m_trafo; }

References m_trafo.

Referenced by Slic3r::multi_material_segmentation_by_painting(), and trafo_centered().

+ Here is the caller graph for this function:

◆ trafo_centered()

Transform3d Slic3r::PrintObject::trafo_centered ( ) const
inline
252 { Transform3d t = this->trafo(); t.pretranslate(Vec3d(- unscale<double>(m_center_offset.x()), - unscale<double>(m_center_offset.y()), 0)); return t; }

References m_center_offset, Eigen::Transform< _Scalar, _Dim, _Mode, _Options >::pretranslate(), and trafo().

Referenced by Slic3r::SeamPlacerImpl::compute_global_occlusion(), Slic3r::SeamPlacerImpl::gather_enforcers_blockers(), and Slic3r::mmu_segmentation_top_and_bottom_layers().

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

◆ update_layer_height_profile()

bool Slic3r::PrintObject::update_layer_height_profile ( const ModelObject model_object,
const SlicingParameters slicing_parameters,
std::vector< coordf_t > &  layer_height_profile 
)
static
2593{
2594 bool updated = false;
2595
2596 if (layer_height_profile.empty()) {
2597 // use the constructor because the assignement is crashing on ASAN OsX
2598 layer_height_profile = model_object.layer_height_profile.get();
2599// layer_height_profile = model_object.layer_height_profile;
2600 // The layer height returned is sampled with high density for the UI layer height painting
2601 // and smoothing tool to work.
2602 updated = true;
2603 }
2604
2605 // Verify the layer_height_profile.
2606 if (!layer_height_profile.empty() &&
2607 // Must not be of even length.
2608 ((layer_height_profile.size() & 1) != 0 ||
2609 // Last entry must be at the top of the object.
2610 std::abs(layer_height_profile[layer_height_profile.size() - 2] - slicing_parameters.object_print_z_max + slicing_parameters.object_print_z_min) > 1e-3))
2611 layer_height_profile.clear();
2612
2613 if (layer_height_profile.empty()) {
2614 //layer_height_profile = layer_height_profile_adaptive(slicing_parameters, model_object.layer_config_ranges, model_object.volumes);
2616 // The layer height profile is already compressed.
2617 updated = true;
2618 }
2619 return updated;
2620}
const std::vector< coordf_t > & get() const
Definition Model.hpp:191
t_layer_config_ranges layer_config_ranges
Definition Model.hpp:341
LayerHeightProfile layer_height_profile
Definition Model.hpp:344
const SlicingParameters & slicing_parameters() const
Definition Print.hpp:309
std::vector< coordf_t > layer_height_profile_from_ranges(const SlicingParameters &slicing_params, const t_layer_config_ranges &layer_config_ranges)
Definition Slicing.cpp:159
coordf_t object_print_z_max
Definition Slicing.hpp:98
coordf_t object_print_z_min
Definition Slicing.hpp:97

References Slic3r::LayerHeightProfile::get(), Slic3r::ModelObject::layer_config_ranges, Slic3r::ModelObject::layer_height_profile, Slic3r::layer_height_profile_from_ranges(), Slic3r::SlicingParameters::object_print_z_max, and Slic3r::SlicingParameters::object_print_z_min.

Referenced by Slic3r::GUI::GLCanvas3D::LayersEditing::adjust_layer_height_profile(), Slic3r::GUI::GLCanvas3D::LayersEditing::generate_layer_height_texture(), Slic3r::GUI::GLCanvas3D::LayersEditing::get_layers_height_data(), and Slic3r::Print::validate().

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

◆ update_slicing_parameters()

void Slic3r::PrintObject::update_slicing_parameters ( )
private
2538{
2541 this->print()->config(), m_config, this->model_object()->max_z(), this->object_extruders());
2542}

Friends And Related Symbol Documentation

◆ Print

friend class Print
friend

◆ PrintBaseWithState< PrintStep, psCount >

friend class PrintBaseWithState< PrintStep, psCount >
friend

Member Data Documentation

◆ m_adaptive_fill_octrees

std::pair<FillAdaptive::OctreePtr, FillAdaptive::OctreePtr> Slic3r::PrintObject::m_adaptive_fill_octrees
private

◆ m_center_offset

Point Slic3r::PrintObject::m_center_offset
private

◆ m_config

PrintObjectConfig Slic3r::PrintObject::m_config
private

◆ m_id

◆ m_instances

std::vector<PrintInstance> Slic3r::PrintObject::m_instances
private

Referenced by instances(), and set_instances().

◆ m_layers

LayerPtrs Slic3r::PrintObject::m_layers
private

◆ m_lightning_generator

FillLightning::GeneratorPtr Slic3r::PrintObject::m_lightning_generator
private

◆ m_model_object

◆ m_print

Print * Slic3r::PrintObjectBaseWithState< Print , PrintObjectStep , COUNT >::m_print
protectedinherited

◆ m_shared_regions

PrintObjectRegions* Slic3r::PrintObject::m_shared_regions { nullptr }
private

◆ m_size

Vec3crd Slic3r::PrintObject::m_size
private

◆ m_slicing_params

SlicingParameters Slic3r::PrintObject::m_slicing_params
private

Referenced by slicing_parameters().

◆ m_state

◆ m_support_layers

SupportLayerPtrs Slic3r::PrintObject::m_support_layers
private

◆ m_trafo

Transform3d Slic3r::PrintObject::m_trafo = Transform3d::Identity()
private

Referenced by trafo().

◆ m_typed_slices

bool Slic3r::PrintObject::m_typed_slices = false
private

Referenced by make_perimeters().

◆ PrintObjectStepEnumSize

constexpr const size_t Slic3r::PrintObjectBaseWithState< Print , PrintObjectStep , COUNT >::PrintObjectStepEnumSize
staticconstexprinherited

◆ PrintType

friend Slic3r::PrintObjectBaseWithState< Print , PrintObjectStep , COUNT >::Print
protectedinherited

◆ s_last_id

size_t Slic3r::ObjectBase::s_last_id = 0
staticprivateinherited

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