1 #include "Exception.hpp"
2 #include "Print.hpp"
3 #include "BoundingBox.hpp"
4 #include "ClipperUtils.hpp"
5 #include "ElephantFootCompensation.hpp"
6 #include "Geometry.hpp"
7 #include "I18N.hpp"
8 #include "Layer.hpp"
9 #include "SupportMaterial.hpp"
10 #include "Surface.hpp"
11 #include "Slicing.hpp"
12 #include "Tesselate.hpp"
13 #include "Utils.hpp"
14 #include "Fill/FillAdaptive.hpp"
15 #include "Format/STL.hpp"
16 
17 #include <utility>
18 #include <boost/log/trivial.hpp>
19 #include <float.h>
20 
21 #include <tbb/parallel_for.h>
22 
23 #include <Shiny/Shiny.h>
24 
25 //! macro used to mark string used at localization,
26 //! return same string
27 #define L(s) Slic3r::I18N::translate(s)
28 
29 #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
30 #define SLIC3R_DEBUG
31 #endif
32 
33 // #define SLIC3R_DEBUG
34 
35 // Make assert active if SLIC3R_DEBUG
36 #ifdef SLIC3R_DEBUG
37     #undef NDEBUG
38     #define DEBUG
39     #define _DEBUG
40     #include "SVG.hpp"
41     #undef assert
42     #include <cassert>
43 #endif
44 
45 namespace Slic3r {
46 
47 // Constructor is called from the main thread, therefore all Model / ModelObject / ModelIntance data are valid.
PrintObject(Print * print,ModelObject * model_object,const Transform3d & trafo,PrintInstances && instances)48 PrintObject::PrintObject(Print* print, ModelObject* model_object, const Transform3d& trafo, PrintInstances&& instances) :
49     PrintObjectBaseWithState(print, model_object),
50     m_trafo(trafo)
51 {
52     // Compute centering offet to be applied to our meshes so that we work with smaller coordinates
53     // requiring less bits to represent Clipper coordinates.
54 
55 	// Snug bounding box of a rotated and scaled object by the 1st instantion, without the instance translation applied.
56 	// All the instances share the transformation matrix with the exception of translation in XY and rotation by Z,
57 	// therefore a bounding box from 1st instance of a ModelObject is good enough for calculating the object center,
58 	// snug height and an approximate bounding box in XY.
59     BoundingBoxf3  bbox        = model_object->raw_bounding_box();
60     Vec3d 		   bbox_center = bbox.center();
61 	// We may need to rotate the bbox / bbox_center from the original instance to the current instance.
62 	double z_diff = Geometry::rotation_diff_z(model_object->instances.front()->get_rotation(), instances.front().model_instance->get_rotation());
63 	if (std::abs(z_diff) > EPSILON) {
64 		auto z_rot  = Eigen::AngleAxisd(z_diff, Vec3d::UnitZ());
65 		bbox 		= bbox.transformed(Transform3d(z_rot));
66 		bbox_center = (z_rot * bbox_center).eval();
67 	}
68 
69     // Center of the transformed mesh (without translation).
70     m_center_offset = Point::new_scale(bbox_center.x(), bbox_center.y());
71     // Size of the transformed mesh. This bounding may not be snug in XY plane, but it is snug in Z.
72     m_size = (bbox.size() * (1. / SCALING_FACTOR)).cast<coord_t>();
73 
74     this->set_instances(std::move(instances));
75 }
76 
set_instances(PrintInstances && instances)77 PrintBase::ApplyStatus PrintObject::set_instances(PrintInstances &&instances)
78 {
79     for (PrintInstance &i : instances)
80     	// Add the center offset, which will be subtracted from the mesh when slicing.
81     	i.shift += m_center_offset;
82     // Invalidate and set copies.
83     PrintBase::ApplyStatus status = PrintBase::APPLY_STATUS_UNCHANGED;
84     bool equal_length = instances.size() == m_instances.size();
85     bool equal = equal_length && std::equal(instances.begin(), instances.end(), m_instances.begin(),
86     	[](const PrintInstance& lhs, const PrintInstance& rhs) { return lhs.model_instance == rhs.model_instance && lhs.shift == rhs.shift; });
87     if (! equal) {
88         status = PrintBase::APPLY_STATUS_CHANGED;
89         if (m_print->invalidate_steps({ psSkirt, psBrim, psGCodeExport }) ||
90             (! equal_length && m_print->invalidate_step(psWipeTower)))
91             status = PrintBase::APPLY_STATUS_INVALIDATED;
92         m_instances = std::move(instances);
93 	    for (PrintInstance &i : m_instances)
94 	    	i.print_object = this;
95     }
96     return status;
97 }
98 
99 // Called by make_perimeters()
100 // 1) Decides Z positions of the layers,
101 // 2) Initializes layers and their regions
102 // 3) Slices the object meshes
103 // 4) Slices the modifier meshes and reclassifies the slices of the object meshes by the slices of the modifier meshes
104 // 5) Applies size compensation (offsets the slices in XY plane)
105 // 6) Replaces bad slices by the slices reconstructed from the upper/lower layer
106 // Resulting expolygons of layer regions are marked as Internal.
slice()107 void PrintObject::slice()
108 {
109     if (! this->set_started(posSlice))
110         return;
111     m_print->set_status(10, L("Processing triangulated mesh"));
112     std::vector<coordf_t> layer_height_profile;
113     this->update_layer_height_profile(*this->model_object(), m_slicing_params, layer_height_profile);
114     m_print->throw_if_canceled();
115     this->_slice(layer_height_profile);
116     m_print->throw_if_canceled();
117     // Fix the model.
118     //FIXME is this the right place to do? It is done repeateadly at the UI and now here at the backend.
119     std::string warning = this->_fix_slicing_errors();
120     m_print->throw_if_canceled();
121     if (! warning.empty())
122         BOOST_LOG_TRIVIAL(info) << warning;
123     // Simplify slices if required.
124     if (m_print->config().resolution)
125         this->simplify_slices(scale_(this->print()->config().resolution));
126     // Update bounding boxes, back up raw slices of complex models.
127     tbb::parallel_for(
128         tbb::blocked_range<size_t>(0, m_layers.size()),
129         [this](const tbb::blocked_range<size_t>& range) {
130             for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
131                 m_print->throw_if_canceled();
132                 Layer &layer = *m_layers[layer_idx];
133                 layer.lslices_bboxes.clear();
134                 layer.lslices_bboxes.reserve(layer.lslices.size());
135                 for (const ExPolygon &expoly : layer.lslices)
136                 	layer.lslices_bboxes.emplace_back(get_extents(expoly));
137                 layer.backup_untyped_slices();
138             }
139         });
140     if (m_layers.empty())
141         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");
142     this->set_done(posSlice);
143 }
144 
145 // 1) Merges typed region slices into stInternal type.
146 // 2) Increases an "extra perimeters" counter at region slices where needed.
147 // 3) Generates perimeters, gap fills and fill regions (fill regions of type stInternal).
make_perimeters()148 void PrintObject::make_perimeters()
149 {
150     // prerequisites
151     this->slice();
152 
153     if (! this->set_started(posPerimeters))
154         return;
155 
156     m_print->set_status(20, L("Generating perimeters"));
157     BOOST_LOG_TRIVIAL(info) << "Generating perimeters..." << log_memory_info();
158 
159     // Revert the typed slices into untyped slices.
160     if (m_typed_slices) {
161         for (Layer *layer : m_layers) {
162             layer->restore_untyped_slices();
163             m_print->throw_if_canceled();
164         }
165         m_typed_slices = false;
166     }
167 
168     // compare each layer to the one below, and mark those slices needing
169     // one additional inner perimeter, like the top of domed objects-
170 
171     // this algorithm makes sure that at least one perimeter is overlapping
172     // but we don't generate any extra perimeter if fill density is zero, as they would be floating
173     // inside the object - infill_only_where_needed should be the method of choice for printing
174     // hollow objects
175     for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) {
176         const PrintRegion &region = *m_print->regions()[region_id];
177         if (! region.config().extra_perimeters || region.config().perimeters == 0 || region.config().fill_density == 0 || this->layer_count() < 2)
178             continue;
179 
180         BOOST_LOG_TRIVIAL(debug) << "Generating extra perimeters for region " << region_id << " in parallel - start";
181         tbb::parallel_for(
182             tbb::blocked_range<size_t>(0, m_layers.size() - 1),
183             [this, &region, region_id](const tbb::blocked_range<size_t>& range) {
184                 for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
185                     m_print->throw_if_canceled();
186                     LayerRegion &layerm                     = *m_layers[layer_idx]->m_regions[region_id];
187                     const LayerRegion &upper_layerm         = *m_layers[layer_idx+1]->m_regions[region_id];
188                     const Polygons upper_layerm_polygons    = upper_layerm.slices;
189                     // Filter upper layer polygons in intersection_ppl by their bounding boxes?
190                     // my $upper_layerm_poly_bboxes= [ map $_->bounding_box, @{$upper_layerm_polygons} ];
191                     const double total_loop_length      = total_length(upper_layerm_polygons);
192                     const coord_t perimeter_spacing     = layerm.flow(frPerimeter).scaled_spacing();
193                     const Flow ext_perimeter_flow       = layerm.flow(frExternalPerimeter);
194                     const coord_t ext_perimeter_width   = ext_perimeter_flow.scaled_width();
195                     const coord_t ext_perimeter_spacing = ext_perimeter_flow.scaled_spacing();
196 
197                     for (Surface &slice : layerm.slices.surfaces) {
198                         for (;;) {
199                             // compute the total thickness of perimeters
200                             const coord_t perimeters_thickness = ext_perimeter_width/2 + ext_perimeter_spacing/2
201                                 + (region.config().perimeters-1 + slice.extra_perimeters) * perimeter_spacing;
202                             // define a critical area where we don't want the upper slice to fall into
203                             // (it should either lay over our perimeters or outside this area)
204                             const coord_t critical_area_depth = coord_t(perimeter_spacing * 1.5);
205                             const Polygons critical_area = diff(
206                                 offset(slice.expolygon, float(- perimeters_thickness)),
207                                 offset(slice.expolygon, float(- perimeters_thickness - critical_area_depth))
208                             );
209                             // check whether a portion of the upper slices falls inside the critical area
210                             const Polylines intersection = intersection_pl(to_polylines(upper_layerm_polygons), critical_area);
211                             // only add an additional loop if at least 30% of the slice loop would benefit from it
212                             if (total_length(intersection) <=  total_loop_length*0.3)
213                                 break;
214                             /*
215                             if (0) {
216                                 require "Slic3r/SVG.pm";
217                                 Slic3r::SVG::output(
218                                     "extra.svg",
219                                     no_arrows   => 1,
220                                     expolygons  => union_ex($critical_area),
221                                     polylines   => [ map $_->split_at_first_point, map $_->p, @{$upper_layerm->slices} ],
222                                 );
223                             }
224                             */
225                             ++ slice.extra_perimeters;
226                         }
227                         #ifdef DEBUG
228                             if (slice.extra_perimeters > 0)
229                                 printf("  adding %d more perimeter(s) at layer %zu\n", slice.extra_perimeters, layer_idx);
230                         #endif
231                     }
232                 }
233             });
234         m_print->throw_if_canceled();
235         BOOST_LOG_TRIVIAL(debug) << "Generating extra perimeters for region " << region_id << " in parallel - end";
236     }
237 
238     BOOST_LOG_TRIVIAL(debug) << "Generating perimeters in parallel - start";
239     tbb::parallel_for(
240         tbb::blocked_range<size_t>(0, m_layers.size()),
241         [this](const tbb::blocked_range<size_t>& range) {
242             for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
243                 m_print->throw_if_canceled();
244                 m_layers[layer_idx]->make_perimeters();
245             }
246         }
247     );
248     m_print->throw_if_canceled();
249     BOOST_LOG_TRIVIAL(debug) << "Generating perimeters in parallel - end";
250 
251     this->set_done(posPerimeters);
252 }
253 
prepare_infill()254 void PrintObject::prepare_infill()
255 {
256     if (! this->set_started(posPrepareInfill))
257         return;
258 
259     m_print->set_status(30, L("Preparing infill"));
260 
261     // This will assign a type (top/bottom/internal) to $layerm->slices.
262     // Then the classifcation of $layerm->slices is transfered onto
263     // the $layerm->fill_surfaces by clipping $layerm->fill_surfaces
264     // by the cummulative area of the previous $layerm->fill_surfaces.
265     this->detect_surfaces_type();
266     m_print->throw_if_canceled();
267 
268     // Decide what surfaces are to be filled.
269     // Here the stTop / stBottomBridge / stBottom infill is turned to just stInternal if zero top / bottom infill layers are configured.
270     // Also tiny stInternal surfaces are turned to stInternalSolid.
271     BOOST_LOG_TRIVIAL(info) << "Preparing fill surfaces..." << log_memory_info();
272     for (auto *layer : m_layers)
273         for (auto *region : layer->m_regions) {
274             region->prepare_fill_surfaces();
275             m_print->throw_if_canceled();
276         }
277 
278     // this will detect bridges and reverse bridges
279     // and rearrange top/bottom/internal surfaces
280     // It produces enlarged overlapping bridging areas.
281     //
282     // 1) stBottomBridge / stBottom infill is grown by 3mm and clipped by the total infill area. Bridges are detected. The areas may overlap.
283     // 2) stTop is grown by 3mm and clipped by the grown bottom areas. The areas may overlap.
284     // 3) Clip the internal surfaces by the grown top/bottom surfaces.
285     // 4) Merge surfaces with the same style. This will mostly get rid of the overlaps.
286     //FIXME This does not likely merge surfaces, which are supported by a material with different colors, but same properties.
287     this->process_external_surfaces();
288     m_print->throw_if_canceled();
289 
290     // Add solid fills to ensure the shell vertical thickness.
291     this->discover_vertical_shells();
292     m_print->throw_if_canceled();
293 
294     // Debugging output.
295 #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
296     for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) {
297         for (const Layer *layer : m_layers) {
298             LayerRegion *layerm = layer->m_regions[region_id];
299             layerm->export_region_slices_to_svg_debug("6_discover_vertical_shells-final");
300             layerm->export_region_fill_surfaces_to_svg_debug("6_discover_vertical_shells-final");
301         } // for each layer
302     } // for each region
303 #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
304 
305     // Detect, which fill surfaces are near external layers.
306     // They will be split in internal and internal-solid surfaces.
307     // The purpose is to add a configurable number of solid layers to support the TOP surfaces
308     // and to add a configurable number of solid layers above the BOTTOM / BOTTOMBRIDGE surfaces
309     // to close these surfaces reliably.
310     //FIXME Vojtech: Is this a good place to add supporting infills below sloping perimeters?
311     this->discover_horizontal_shells();
312     m_print->throw_if_canceled();
313 
314 #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
315     for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) {
316         for (const Layer *layer : m_layers) {
317             LayerRegion *layerm = layer->m_regions[region_id];
318             layerm->export_region_slices_to_svg_debug("7_discover_horizontal_shells-final");
319             layerm->export_region_fill_surfaces_to_svg_debug("7_discover_horizontal_shells-final");
320         } // for each layer
321     } // for each region
322 #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
323 
324     // Only active if config->infill_only_where_needed. This step trims the sparse infill,
325     // so it acts as an internal support. It maintains all other infill types intact.
326     // Here the internal surfaces and perimeters have to be supported by the sparse infill.
327     //FIXME The surfaces are supported by a sparse infill, but the sparse infill is only as large as the area to support.
328     // Likely the sparse infill will not be anchored correctly, so it will not work as intended.
329     // Also one wishes the perimeters to be supported by a full infill.
330     this->clip_fill_surfaces();
331     m_print->throw_if_canceled();
332 
333 #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
334     for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) {
335         for (const Layer *layer : m_layers) {
336             LayerRegion *layerm = layer->m_regions[region_id];
337             layerm->export_region_slices_to_svg_debug("8_clip_surfaces-final");
338             layerm->export_region_fill_surfaces_to_svg_debug("8_clip_surfaces-final");
339         } // for each layer
340     } // for each region
341 #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
342 
343     // the following step needs to be done before combination because it may need
344     // to remove only half of the combined infill
345     this->bridge_over_infill();
346     m_print->throw_if_canceled();
347 
348     // combine fill surfaces to honor the "infill every N layers" option
349     this->combine_infill();
350     m_print->throw_if_canceled();
351 
352 #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
353     for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) {
354         for (const Layer *layer : m_layers) {
355             LayerRegion *layerm = layer->m_regions[region_id];
356             layerm->export_region_slices_to_svg_debug("9_prepare_infill-final");
357             layerm->export_region_fill_surfaces_to_svg_debug("9_prepare_infill-final");
358         } // for each layer
359     } // for each region
360     for (const Layer *layer : m_layers) {
361         layer->export_region_slices_to_svg_debug("9_prepare_infill-final");
362         layer->export_region_fill_surfaces_to_svg_debug("9_prepare_infill-final");
363     } // for each layer
364 #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
365 
366     this->set_done(posPrepareInfill);
367 }
368 
infill()369 void PrintObject::infill()
370 {
371     // prerequisites
372     this->prepare_infill();
373 
374     if (this->set_started(posInfill)) {
375         auto [adaptive_fill_octree, support_fill_octree] = this->prepare_adaptive_infill_data();
376 
377         BOOST_LOG_TRIVIAL(debug) << "Filling layers in parallel - start";
378         tbb::parallel_for(
379             tbb::blocked_range<size_t>(0, m_layers.size()),
380             [this, &adaptive_fill_octree = adaptive_fill_octree, &support_fill_octree = support_fill_octree](const tbb::blocked_range<size_t>& range) {
381                 for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
382                     m_print->throw_if_canceled();
383                     m_layers[layer_idx]->make_fills(adaptive_fill_octree.get(), support_fill_octree.get());
384                 }
385             }
386         );
387         m_print->throw_if_canceled();
388         BOOST_LOG_TRIVIAL(debug) << "Filling layers in parallel - end";
389         /*  we could free memory now, but this would make this step not idempotent
390         ### $_->fill_surfaces->clear for map @{$_->regions}, @{$object->layers};
391         */
392         this->set_done(posInfill);
393     }
394 }
395 
ironing()396 void PrintObject::ironing()
397 {
398     if (this->set_started(posIroning)) {
399         BOOST_LOG_TRIVIAL(debug) << "Ironing in parallel - start";
400         tbb::parallel_for(
401             tbb::blocked_range<size_t>(1, m_layers.size()),
402             [this](const tbb::blocked_range<size_t>& range) {
403                 for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
404                     m_print->throw_if_canceled();
405                     m_layers[layer_idx]->make_ironing();
406                 }
407             }
408         );
409         m_print->throw_if_canceled();
410         BOOST_LOG_TRIVIAL(debug) << "Ironing in parallel - end";
411         this->set_done(posIroning);
412     }
413 }
414 
generate_support_material()415 void PrintObject::generate_support_material()
416 {
417     if (this->set_started(posSupportMaterial)) {
418         this->clear_support_layers();
419         if ((m_config.support_material || m_config.raft_layers > 0) && m_layers.size() > 1) {
420             m_print->set_status(85, L("Generating support material"));
421             this->_generate_support_material();
422             m_print->throw_if_canceled();
423         } else {
424 #if 0
425             // Printing without supports. Empty layer means some objects or object parts are levitating,
426             // therefore they cannot be printed without supports.
427             for (const Layer *layer : m_layers)
428                 if (layer->empty())
429                     throw Slic3r::SlicingError("Levitating objects cannot be printed without supports.");
430 #endif
431         }
432         this->set_done(posSupportMaterial);
433     }
434 }
435 
prepare_adaptive_infill_data()436 std::pair<FillAdaptive::OctreePtr, FillAdaptive::OctreePtr> PrintObject::prepare_adaptive_infill_data()
437 {
438     using namespace FillAdaptive;
439 
440     auto [adaptive_line_spacing, support_line_spacing] = adaptive_fill_line_spacing(*this);
441     if ((adaptive_line_spacing == 0. && support_line_spacing == 0.) || this->layers().empty())
442         return std::make_pair(OctreePtr(), OctreePtr());
443 
444     indexed_triangle_set mesh = this->model_object()->raw_indexed_triangle_set();
445     // Rotate mesh and build octree on it with axis-aligned (standart base) cubes.
446     Transform3d m = m_trafo;
447     m.pretranslate(Vec3d(- unscale<float>(m_center_offset.x()), - unscale<float>(m_center_offset.y()), 0));
448     auto to_octree = transform_to_octree().toRotationMatrix();
449     its_transform(mesh, to_octree * m, true);
450 
451     // Triangulate internal bridging surfaces.
452     std::vector<std::vector<Vec3d>> overhangs(this->layers().size());
453     tbb::parallel_for(
454         tbb::blocked_range<int>(0, int(m_layers.size()) - 1),
455         [this, &to_octree, &overhangs](const tbb::blocked_range<int> &range) {
456             std::vector<Vec3d> &out = overhangs[range.begin()];
457             for (int idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) {
458                 m_print->throw_if_canceled();
459                 const Layer *layer = this->layers()[idx_layer];
460                 for (const LayerRegion *layerm : layer->regions())
461                     for (const Surface &surface : layerm->fill_surfaces.surfaces)
462                         if (surface.surface_type == stInternalBridge)
463                             append(out, triangulate_expolygon_3d(surface.expolygon, layer->bottom_z()));
464             }
465             for (Vec3d &p : out)
466                 p = (to_octree * p).eval();
467         });
468     // and gather them.
469     for (size_t i = 1; i < overhangs.size(); ++ i)
470         append(overhangs.front(), std::move(overhangs[i]));
471 
472     return std::make_pair(
473         adaptive_line_spacing ? build_octree(mesh, overhangs.front(), adaptive_line_spacing, false) : OctreePtr(),
474         support_line_spacing  ? build_octree(mesh, overhangs.front(), support_line_spacing, true) : OctreePtr());
475 }
476 
clear_layers()477 void PrintObject::clear_layers()
478 {
479     for (Layer *l : m_layers)
480         delete l;
481     m_layers.clear();
482 }
483 
add_layer(int id,coordf_t height,coordf_t print_z,coordf_t slice_z)484 Layer* PrintObject::add_layer(int id, coordf_t height, coordf_t print_z, coordf_t slice_z)
485 {
486     m_layers.emplace_back(new Layer(id, this, height, print_z, slice_z));
487     return m_layers.back();
488 }
489 
clear_support_layers()490 void PrintObject::clear_support_layers()
491 {
492     for (Layer *l : m_support_layers)
493         delete l;
494     m_support_layers.clear();
495 }
496 
add_support_layer(int id,coordf_t height,coordf_t print_z)497 SupportLayer* PrintObject::add_support_layer(int id, coordf_t height, coordf_t print_z)
498 {
499     m_support_layers.emplace_back(new SupportLayer(id, this, height, print_z, -1));
500     return m_support_layers.back();
501 }
502 
insert_support_layer(SupportLayerPtrs::const_iterator pos,size_t id,coordf_t height,coordf_t print_z,coordf_t slice_z)503 SupportLayerPtrs::const_iterator PrintObject::insert_support_layer(SupportLayerPtrs::const_iterator pos, size_t id, coordf_t height, coordf_t print_z, coordf_t slice_z)
504 {
505     return m_support_layers.insert(pos, new SupportLayer(id, this, height, print_z, slice_z));
506 }
507 
508 // Called by Print::apply().
509 // This method only accepts PrintObjectConfig and PrintRegionConfig option keys.
invalidate_state_by_config_options(const std::vector<t_config_option_key> & opt_keys)510 bool PrintObject::invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys)
511 {
512     if (opt_keys.empty())
513         return false;
514 
515     std::vector<PrintObjectStep> steps;
516     bool invalidated = false;
517     for (const t_config_option_key &opt_key : opt_keys) {
518         if (   opt_key == "perimeters"
519             || opt_key == "extra_perimeters"
520             || opt_key == "gap_fill_speed"
521             || opt_key == "overhangs"
522             || opt_key == "first_layer_extrusion_width"
523             || opt_key == "perimeter_extrusion_width"
524             || opt_key == "infill_overlap"
525             || opt_key == "thin_walls"
526             || opt_key == "external_perimeters_first") {
527             steps.emplace_back(posPerimeters);
528         } else if (
529                opt_key == "layer_height"
530             || opt_key == "first_layer_height"
531             || opt_key == "raft_layers"
532             || opt_key == "slice_closing_radius") {
533             steps.emplace_back(posSlice);
534 		} else if (
535                opt_key == "clip_multipart_objects"
536             || opt_key == "elefant_foot_compensation"
537             || opt_key == "support_material_contact_distance"
538             || opt_key == "xy_size_compensation") {
539             steps.emplace_back(posSlice);
540         } else if (opt_key == "support_material") {
541             steps.emplace_back(posSupportMaterial);
542             if (m_config.support_material_contact_distance == 0.) {
543             	// Enabling / disabling supports while soluble support interface is enabled.
544             	// This changes the bridging logic (bridging enabled without supports, disabled with supports).
545             	// Reset everything.
546             	// See GH #1482 for details.
547 	            steps.emplace_back(posSlice);
548 	        }
549         } else if (
550         	   opt_key == "support_material_auto"
551             || opt_key == "support_material_angle"
552             || opt_key == "support_material_buildplate_only"
553             || opt_key == "support_material_enforce_layers"
554             || opt_key == "support_material_extruder"
555             || opt_key == "support_material_extrusion_width"
556             || opt_key == "support_material_interface_layers"
557             || opt_key == "support_material_interface_contact_loops"
558             || opt_key == "support_material_interface_extruder"
559             || opt_key == "support_material_interface_spacing"
560             || opt_key == "support_material_pattern"
561             || opt_key == "support_material_xy_spacing"
562             || opt_key == "support_material_spacing"
563             || opt_key == "support_material_synchronize_layers"
564             || opt_key == "support_material_threshold"
565             || opt_key == "support_material_with_sheath"
566             || opt_key == "dont_support_bridges"
567             || opt_key == "first_layer_extrusion_width") {
568             steps.emplace_back(posSupportMaterial);
569         } else if (opt_key == "bottom_solid_layers") {
570             steps.emplace_back(posPrepareInfill);
571             if(m_print->config().spiral_vase) {
572                 // Changing the number of bottom layers when a spiral vase is enabled requires re-slicing the object again.
573                 // Otherwise, holes in the bottom layers could be filled, as is reported in GH #5528.
574                 steps.emplace_back(posSlice);
575             }
576         } else if (
577                opt_key == "interface_shells"
578             || opt_key == "infill_only_where_needed"
579             || opt_key == "infill_every_layers"
580             || opt_key == "solid_infill_every_layers"
581             || opt_key == "bottom_solid_min_thickness"
582             || opt_key == "top_solid_layers"
583             || opt_key == "top_solid_min_thickness"
584             || opt_key == "solid_infill_below_area"
585             || opt_key == "infill_extruder"
586             || opt_key == "solid_infill_extruder"
587             || opt_key == "infill_extrusion_width"
588             || opt_key == "ensure_vertical_shell_thickness"
589             || opt_key == "bridge_angle") {
590             steps.emplace_back(posPrepareInfill);
591         } else if (
592                opt_key == "top_fill_pattern"
593             || opt_key == "bottom_fill_pattern"
594             || opt_key == "external_fill_link_max_length"
595             || opt_key == "fill_angle"
596             || opt_key == "fill_pattern"
597             || opt_key == "infill_anchor"
598             || opt_key == "infill_anchor_max"
599             || opt_key == "top_infill_extrusion_width"
600             || opt_key == "first_layer_extrusion_width") {
601             steps.emplace_back(posInfill);
602         } else if (
603                opt_key == "fill_density"
604             || opt_key == "solid_infill_extrusion_width") {
605             steps.emplace_back(posPerimeters);
606             steps.emplace_back(posPrepareInfill);
607         } else if (
608                opt_key == "external_perimeter_extrusion_width"
609             || opt_key == "perimeter_extruder") {
610             steps.emplace_back(posPerimeters);
611             steps.emplace_back(posSupportMaterial);
612         } else if (opt_key == "bridge_flow_ratio") {
613             if (m_config.support_material_contact_distance > 0.) {
614             	// Only invalidate due to bridging if bridging is enabled.
615             	// If later "support_material_contact_distance" is modified, the complete PrintObject is invalidated anyway.
616             	steps.emplace_back(posPerimeters);
617             	steps.emplace_back(posInfill);
618 	            steps.emplace_back(posSupportMaterial);
619 	        }
620         } else if (
621                opt_key == "seam_position"
622             || opt_key == "seam_preferred_direction"
623             || opt_key == "seam_preferred_direction_jitter"
624             || opt_key == "support_material_speed"
625             || opt_key == "support_material_interface_speed"
626             || opt_key == "bridge_speed"
627             || opt_key == "external_perimeter_speed"
628             || opt_key == "infill_speed"
629             || opt_key == "perimeter_speed"
630             || opt_key == "small_perimeter_speed"
631             || opt_key == "solid_infill_speed"
632             || opt_key == "top_solid_infill_speed") {
633             invalidated |= m_print->invalidate_step(psGCodeExport);
634         } else if (
635                opt_key == "wipe_into_infill"
636             || opt_key == "wipe_into_objects") {
637             invalidated |= m_print->invalidate_step(psWipeTower);
638             invalidated |= m_print->invalidate_step(psGCodeExport);
639         } else {
640             // for legacy, if we can't handle this option let's invalidate all steps
641             this->invalidate_all_steps();
642             invalidated = true;
643         }
644     }
645 
646     sort_remove_duplicates(steps);
647     for (PrintObjectStep step : steps)
648         invalidated |= this->invalidate_step(step);
649     return invalidated;
650 }
651 
invalidate_step(PrintObjectStep step)652 bool PrintObject::invalidate_step(PrintObjectStep step)
653 {
654 	bool invalidated = Inherited::invalidate_step(step);
655 
656     // propagate to dependent steps
657     if (step == posPerimeters) {
658 		invalidated |= this->invalidate_steps({ posPrepareInfill, posInfill, posIroning });
659         invalidated |= m_print->invalidate_steps({ psSkirt, psBrim });
660     } else if (step == posPrepareInfill) {
661         invalidated |= this->invalidate_steps({ posInfill, posIroning });
662     } else if (step == posInfill) {
663         invalidated |= this->invalidate_steps({ posIroning });
664         invalidated |= m_print->invalidate_steps({ psSkirt, psBrim });
665     } else if (step == posSlice) {
666 		invalidated |= this->invalidate_steps({ posPerimeters, posPrepareInfill, posInfill, posIroning, posSupportMaterial });
667 		invalidated |= m_print->invalidate_steps({ psSkirt, psBrim });
668         this->m_slicing_params.valid = false;
669     } else if (step == posSupportMaterial) {
670         invalidated |= m_print->invalidate_steps({ psSkirt, psBrim });
671         this->m_slicing_params.valid = false;
672     }
673 
674     // Wipe tower depends on the ordering of extruders, which in turn depends on everything.
675     // It also decides about what the wipe_into_infill / wipe_into_object features will do,
676     // and that too depends on many of the settings.
677     invalidated |= m_print->invalidate_step(psWipeTower);
678     // Invalidate G-code export in any case.
679     invalidated |= m_print->invalidate_step(psGCodeExport);
680     return invalidated;
681 }
682 
invalidate_all_steps()683 bool PrintObject::invalidate_all_steps()
684 {
685 	// First call the "invalidate" functions, which may cancel background processing.
686     bool result = Inherited::invalidate_all_steps() | m_print->invalidate_all_steps();
687 	// Then reset some of the depending values.
688 	this->m_slicing_params.valid = false;
689 	this->region_volumes.clear();
690 	return result;
691 }
692 
has_support_material() const693 bool PrintObject::has_support_material() const
694 {
695     return m_config.support_material
696         || m_config.raft_layers > 0
697         || m_config.support_material_enforce_layers > 0;
698 }
699 
first_printing_region(const PrintObject & print_object)700 static const PrintRegion* first_printing_region(const PrintObject &print_object)
701 {
702     for (size_t idx_region = 0; idx_region < print_object.region_volumes.size(); ++ idx_region)
703     	if (!print_object.region_volumes.empty())
704     		return print_object.print()->regions()[idx_region];
705     return nullptr;
706 }
707 
708 // This function analyzes slices of a region (SurfaceCollection slices).
709 // Each region slice (instance of Surface) is analyzed, whether it is supported or whether it is the top surface.
710 // Initially all slices are of type stInternal.
711 // Slices are compared against the top / bottom slices and regions and classified to the following groups:
712 // stTop          - Part of a region, which is not covered by any upper layer. This surface will be filled with a top solid infill.
713 // stBottomBridge - Part of a region, which is not fully supported, but it hangs in the air, or it hangs losely on a support or a raft.
714 // stBottom       - Part of a region, which is not supported by the same region, but it is supported either by another region, or by a soluble interface layer.
715 // stInternal     - Part of a region, which is supported by the same region type.
716 // If a part of a region is of stBottom and stTop, the stBottom wins.
detect_surfaces_type()717 void PrintObject::detect_surfaces_type()
718 {
719     BOOST_LOG_TRIVIAL(info) << "Detecting solid surfaces..." << log_memory_info();
720 
721     // Interface shells: the intersecting parts are treated as self standing objects supporting each other.
722     // Each of the objects will have a full number of top / bottom layers, even if these top / bottom layers
723     // are completely hidden inside a collective body of intersecting parts.
724     // This is useful if one of the parts is to be dissolved, or if it is transparent and the internal shells
725     // should be visible.
726     bool spiral_vase      = this->print()->config().spiral_vase.value;
727     bool interface_shells = ! spiral_vase && m_config.interface_shells.value;
728     size_t num_layers     = spiral_vase ? std::min(size_t(first_printing_region(*this)->config().bottom_solid_layers), m_layers.size()) : m_layers.size();
729 
730     for (size_t idx_region = 0; idx_region < this->region_volumes.size(); ++ idx_region) {
731         BOOST_LOG_TRIVIAL(debug) << "Detecting solid surfaces for region " << idx_region << " in parallel - start";
732 #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
733         for (Layer *layer : m_layers)
734             layer->m_regions[idx_region]->export_region_fill_surfaces_to_svg_debug("1_detect_surfaces_type-initial");
735 #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
736 
737         // If interface shells are allowed, the region->surfaces cannot be overwritten as they may be used by other threads.
738         // Cache the result of the following parallel_loop.
739         std::vector<Surfaces> surfaces_new;
740         if (interface_shells)
741             surfaces_new.assign(num_layers, Surfaces());
742 
743         tbb::parallel_for(
744             tbb::blocked_range<size_t>(0,
745             	spiral_vase ?
746             		// In spiral vase mode, reserve the last layer for the top surface if more than 1 layer is planned for the vase bottom.
747             		((num_layers > 1) ? num_layers - 1 : num_layers) :
748             		// In non-spiral vase mode, go over all layers.
749             		m_layers.size()),
750             [this, idx_region, interface_shells, &surfaces_new](const tbb::blocked_range<size_t>& range) {
751                 // If we have raft layers, consider bottom layer as a bridge just like any other bottom surface lying on the void.
752                 SurfaceType surface_type_bottom_1st =
753                     (m_config.raft_layers.value > 0 && m_config.support_material_contact_distance.value > 0) ?
754                     stBottomBridge : stBottom;
755                 // If we have soluble support material, don't bridge. The overhang will be squished against a soluble layer separating
756                 // the support from the print.
757                 SurfaceType surface_type_bottom_other =
758                     (m_config.support_material.value && m_config.support_material_contact_distance.value == 0) ?
759                     stBottom : stBottomBridge;
760                 for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) {
761                     m_print->throw_if_canceled();
762                     // BOOST_LOG_TRIVIAL(trace) << "Detecting solid surfaces for region " << idx_region << " and layer " << layer->print_z;
763                     Layer       *layer  = m_layers[idx_layer];
764                     LayerRegion *layerm = layer->m_regions[idx_region];
765                     // comparison happens against the *full* slices (considering all regions)
766                     // unless internal shells are requested
767                     Layer       *upper_layer = (idx_layer + 1 < this->layer_count()) ? m_layers[idx_layer + 1] : nullptr;
768                     Layer       *lower_layer = (idx_layer > 0) ? m_layers[idx_layer - 1] : nullptr;
769                     // collapse very narrow parts (using the safety offset in the diff is not enough)
770                     float        offset = layerm->flow(frExternalPerimeter).scaled_width() / 10.f;
771 
772                     Polygons     layerm_slices_surfaces = to_polygons(layerm->slices.surfaces);
773 
774                     // find top surfaces (difference between current surfaces
775                     // of current layer and upper one)
776                     Surfaces top;
777                     if (upper_layer) {
778                         Polygons upper_slices = interface_shells ?
779                             to_polygons(upper_layer->m_regions[idx_region]->slices.surfaces) :
780                             to_polygons(upper_layer->lslices);
781                         surfaces_append(top,
782                             //FIXME implement offset2_ex working over ExPolygons, that should be a bit more efficient than calling offset_ex twice.
783                             offset_ex(offset_ex(diff_ex(layerm_slices_surfaces, upper_slices, true), -offset), offset),
784                             stTop);
785                     } else {
786                         // if no upper layer, all surfaces of this one are solid
787                         // we clone surfaces because we're going to clear the slices collection
788                         top = layerm->slices.surfaces;
789                         for (Surface &surface : top)
790                             surface.surface_type = stTop;
791                     }
792 
793                     // Find bottom surfaces (difference between current surfaces of current layer and lower one).
794                     Surfaces bottom;
795                     if (lower_layer) {
796 #if 0
797                         //FIXME Why is this branch failing t\multi.t ?
798                         Polygons lower_slices = interface_shells ?
799                             to_polygons(lower_layer->get_region(idx_region)->slices.surfaces) :
800                             to_polygons(lower_layer->slices);
801                         surfaces_append(bottom,
802                             offset2_ex(diff(layerm_slices_surfaces, lower_slices, true), -offset, offset),
803                             surface_type_bottom_other);
804 #else
805                         // Any surface lying on the void is a true bottom bridge (an overhang)
806                         surfaces_append(
807                             bottom,
808                             offset2_ex(
809                                 diff(layerm_slices_surfaces, to_polygons(lower_layer->lslices), true),
810                                 -offset, offset),
811                             surface_type_bottom_other);
812                         // if user requested internal shells, we need to identify surfaces
813                         // lying on other slices not belonging to this region
814                         if (interface_shells) {
815                             // non-bridging bottom surfaces: any part of this layer lying
816                             // on something else, excluding those lying on our own region
817                             surfaces_append(
818                                 bottom,
819                                 offset2_ex(
820                                     diff(
821                                         intersection(layerm_slices_surfaces, to_polygons(lower_layer->lslices)), // supported
822                                         to_polygons(lower_layer->m_regions[idx_region]->slices.surfaces),
823                                         true),
824                                     -offset, offset),
825                                 stBottom);
826                         }
827 #endif
828                     } else {
829                         // if no lower layer, all surfaces of this one are solid
830                         // we clone surfaces because we're going to clear the slices collection
831                         bottom = layerm->slices.surfaces;
832                         for (Surface &surface : bottom)
833                             surface.surface_type = surface_type_bottom_1st;
834                     }
835 
836                     // now, if the object contained a thin membrane, we could have overlapping bottom
837                     // and top surfaces; let's do an intersection to discover them and consider them
838                     // as bottom surfaces (to allow for bridge detection)
839                     if (! top.empty() && ! bottom.empty()) {
840         //                Polygons overlapping = intersection(to_polygons(top), to_polygons(bottom));
841         //                Slic3r::debugf "  layer %d contains %d membrane(s)\n", $layerm->layer->id, scalar(@$overlapping)
842         //                    if $Slic3r::debug;
843                         Polygons top_polygons = to_polygons(std::move(top));
844                         top.clear();
845                         surfaces_append(top,
846                             diff_ex(top_polygons, to_polygons(bottom), false),
847                             stTop);
848                     }
849 
850         #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
851                     {
852                         static int iRun = 0;
853                         std::vector<std::pair<Slic3r::ExPolygons, SVG::ExPolygonAttributes>> expolygons_with_attributes;
854                         expolygons_with_attributes.emplace_back(std::make_pair(union_ex(top),                           SVG::ExPolygonAttributes("green")));
855                         expolygons_with_attributes.emplace_back(std::make_pair(union_ex(bottom),                        SVG::ExPolygonAttributes("brown")));
856                         expolygons_with_attributes.emplace_back(std::make_pair(to_expolygons(layerm->slices.surfaces),  SVG::ExPolygonAttributes("black")));
857                         SVG::export_expolygons(debug_out_path("1_detect_surfaces_type_%d_region%d-layer_%f.svg", iRun ++, idx_region, layer->print_z).c_str(), expolygons_with_attributes);
858                     }
859         #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
860 
861                     // save surfaces to layer
862                     Surfaces &surfaces_out = interface_shells ? surfaces_new[idx_layer] : layerm->slices.surfaces;
863                     surfaces_out.clear();
864 
865                     // find internal surfaces (difference between top/bottom surfaces and others)
866                     {
867                         Polygons topbottom = to_polygons(top);
868                         polygons_append(topbottom, to_polygons(bottom));
869                         surfaces_append(surfaces_out,
870                             diff_ex(layerm_slices_surfaces, topbottom, false),
871                             stInternal);
872                     }
873 
874                     surfaces_append(surfaces_out, std::move(top));
875                     surfaces_append(surfaces_out, std::move(bottom));
876 
877         //            Slic3r::debugf "  layer %d has %d bottom, %d top and %d internal surfaces\n",
878         //                $layerm->layer->id, scalar(@bottom), scalar(@top), scalar(@internal) if $Slic3r::debug;
879 
880         #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
881                     layerm->export_region_slices_to_svg_debug("detect_surfaces_type-final");
882         #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
883                 }
884             }
885         ); // for each layer of a region
886         m_print->throw_if_canceled();
887 
888         if (interface_shells) {
889             // Move surfaces_new to layerm->slices.surfaces
890             for (size_t idx_layer = 0; idx_layer < num_layers; ++ idx_layer)
891                 m_layers[idx_layer]->m_regions[idx_region]->slices.surfaces = std::move(surfaces_new[idx_layer]);
892         }
893 
894         if (spiral_vase) {
895         	if (num_layers > 1)
896 	        	// Turn the last bottom layer infill to a top infill, so it will be extruded with a proper pattern.
897 	        	m_layers[num_layers - 1]->m_regions[idx_region]->slices.set_type(stTop);
898 	        for (size_t i = num_layers; i < m_layers.size(); ++ i)
899 	        	m_layers[i]->m_regions[idx_region]->slices.set_type(stInternal);
900         }
901 
902         BOOST_LOG_TRIVIAL(debug) << "Detecting solid surfaces for region " << idx_region << " - clipping in parallel - start";
903         // Fill in layerm->fill_surfaces by trimming the layerm->slices by the cummulative layerm->fill_surfaces.
904         tbb::parallel_for(
905             tbb::blocked_range<size_t>(0, m_layers.size()),
906             [this, idx_region, interface_shells](const tbb::blocked_range<size_t>& range) {
907                 for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) {
908                     m_print->throw_if_canceled();
909                     LayerRegion *layerm = m_layers[idx_layer]->m_regions[idx_region];
910                     layerm->slices_to_fill_surfaces_clipped();
911 #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
912                     layerm->export_region_fill_surfaces_to_svg_debug("1_detect_surfaces_type-final");
913 #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
914                 } // for each layer of a region
915             });
916         m_print->throw_if_canceled();
917         BOOST_LOG_TRIVIAL(debug) << "Detecting solid surfaces for region " << idx_region << " - clipping in parallel - end";
918     } // for each this->print->region_count
919 
920     // 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.)
921     m_typed_slices = true;
922 }
923 
process_external_surfaces()924 void PrintObject::process_external_surfaces()
925 {
926     BOOST_LOG_TRIVIAL(info) << "Processing external surfaces..." << log_memory_info();
927 
928     // Cached surfaces covered by some extrusion, defining regions, over which the from the surfaces one layer higher are allowed to expand.
929     std::vector<Polygons> surfaces_covered;
930     // 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
931     // over voids, which are supported by the layer below.
932     bool 				  has_voids = false;
933 	for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id)
934 		if (! this->region_volumes.empty() && this->print()->regions()[region_id]->config().fill_density == 0) {
935 			has_voids = true;
936 			break;
937 		}
938 	if (has_voids && m_layers.size() > 1) {
939 	    // All but stInternal fill surfaces will get expanded and possibly trimmed.
940 	    std::vector<unsigned char> layer_expansions_and_voids(m_layers.size(), false);
941 	    for (size_t layer_idx = 0; layer_idx < m_layers.size(); ++ layer_idx) {
942 	    	const Layer *layer = m_layers[layer_idx];
943 	    	bool expansions = false;
944 	    	bool voids      = false;
945 	    	for (const LayerRegion *layerm : layer->regions()) {
946 	    		for (const Surface &surface : layerm->fill_surfaces.surfaces) {
947 	    			if (surface.surface_type == stInternal)
948 	    				voids = true;
949 	    			else
950 	    				expansions = true;
951 	    			if (voids && expansions) {
952 	    				layer_expansions_and_voids[layer_idx] = true;
953 	    				goto end;
954 	    			}
955 	    		}
956 	    	}
957 		end:;
958 		}
959 	    BOOST_LOG_TRIVIAL(debug) << "Collecting surfaces covered with extrusions in parallel - start";
960 	    surfaces_covered.resize(m_layers.size() - 1, Polygons());
961     	auto unsupported_width = - float(scale_(0.3 * EXTERNAL_INFILL_MARGIN));
962 	    tbb::parallel_for(
963 	        tbb::blocked_range<size_t>(0, m_layers.size() - 1),
964 	        [this, &surfaces_covered, &layer_expansions_and_voids, unsupported_width](const tbb::blocked_range<size_t>& range) {
965 	            for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx)
966 	            	if (layer_expansions_and_voids[layer_idx + 1]) {
967 		                m_print->throw_if_canceled();
968 		                Polygons voids;
969 		                for (const LayerRegion *layerm : m_layers[layer_idx]->regions()) {
970 		                	if (layerm->region()->config().fill_density.value == 0.)
971 		                		for (const Surface &surface : layerm->fill_surfaces.surfaces)
972 		                			// Shrink the holes, let the layer above expand slightly inside the unsupported areas.
973 		                			polygons_append(voids, offset(surface.expolygon, unsupported_width));
974 		                }
975 		                surfaces_covered[layer_idx] = diff(to_polygons(this->m_layers[layer_idx]->lslices), voids);
976 	            	}
977 	        }
978 	    );
979 	    m_print->throw_if_canceled();
980 	    BOOST_LOG_TRIVIAL(debug) << "Collecting surfaces covered with extrusions in parallel - end";
981 	}
982 
983 	for (size_t region_id = 0; region_id < this->region_volumes.size(); ++region_id) {
984         BOOST_LOG_TRIVIAL(debug) << "Processing external surfaces for region " << region_id << " in parallel - start";
985         tbb::parallel_for(
986             tbb::blocked_range<size_t>(0, m_layers.size()),
987             [this, &surfaces_covered, region_id](const tbb::blocked_range<size_t>& range) {
988                 for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
989                     m_print->throw_if_canceled();
990                     // BOOST_LOG_TRIVIAL(trace) << "Processing external surface, layer" << m_layers[layer_idx]->print_z;
991                     m_layers[layer_idx]->get_region((int)region_id)->process_external_surfaces(
992                     	(layer_idx == 0) ? nullptr : m_layers[layer_idx - 1],
993                     	(layer_idx == 0 || surfaces_covered.empty() || surfaces_covered[layer_idx - 1].empty()) ? nullptr : &surfaces_covered[layer_idx - 1]);
994                 }
995             }
996         );
997         m_print->throw_if_canceled();
998         BOOST_LOG_TRIVIAL(debug) << "Processing external surfaces for region " << region_id << " in parallel - end";
999     }
1000 }
1001 
discover_vertical_shells()1002 void PrintObject::discover_vertical_shells()
1003 {
1004     PROFILE_FUNC();
1005 
1006     BOOST_LOG_TRIVIAL(info) << "Discovering vertical shells..." << log_memory_info();
1007 
1008     struct DiscoverVerticalShellsCacheEntry
1009     {
1010         // Collected polygons, offsetted
1011         Polygons    top_surfaces;
1012         Polygons    bottom_surfaces;
1013         Polygons    holes;
1014     };
1015     bool     spiral_vase      = this->print()->config().spiral_vase.value;
1016     size_t   num_layers       = spiral_vase ? std::min(size_t(first_printing_region(*this)->config().bottom_solid_layers), m_layers.size()) : m_layers.size();
1017     coordf_t min_layer_height = this->slicing_parameters().min_layer_height;
1018     // Does this region possibly produce more than 1 top or bottom layer?
1019     auto has_extra_layers_fn = [min_layer_height](const PrintRegionConfig &config) {
1020 	    auto num_extra_layers = [min_layer_height](int num_solid_layers, coordf_t min_shell_thickness) {
1021 	    	if (num_solid_layers == 0)
1022 	    		return 0;
1023 	    	int n = num_solid_layers - 1;
1024 	    	int n2 = int(ceil(min_shell_thickness / min_layer_height));
1025 	    	return std::max(n, n2 - 1);
1026 	    };
1027     	return num_extra_layers(config.top_solid_layers, config.top_solid_min_thickness) +
1028 	    	   num_extra_layers(config.bottom_solid_layers, config.bottom_solid_min_thickness) > 0;
1029     };
1030     std::vector<DiscoverVerticalShellsCacheEntry> cache_top_botom_regions(num_layers, DiscoverVerticalShellsCacheEntry());
1031     bool top_bottom_surfaces_all_regions = this->region_volumes.size() > 1 && ! m_config.interface_shells.value;
1032     if (top_bottom_surfaces_all_regions) {
1033         // This is a multi-material print and interface_shells are disabled, meaning that the vertical shell thickness
1034         // is calculated over all materials.
1035         // Is the "ensure vertical wall thickness" applicable to any region?
1036         bool has_extra_layers = false;
1037         for (size_t idx_region = 0; idx_region < this->region_volumes.size(); ++idx_region) {
1038             const PrintRegionConfig &config = m_print->get_region(idx_region)->config();
1039             if (config.ensure_vertical_shell_thickness.value && has_extra_layers_fn(config)) {
1040                 has_extra_layers = true;
1041                 break;
1042             }
1043         }
1044         if (! has_extra_layers)
1045             // The "ensure vertical wall thickness" feature is not applicable to any of the regions. Quit.
1046             return;
1047         BOOST_LOG_TRIVIAL(debug) << "Discovering vertical shells in parallel - start : cache top / bottom";
1048         //FIXME Improve the heuristics for a grain size.
1049         size_t grain_size = std::max(num_layers / 16, size_t(1));
1050         tbb::parallel_for(
1051             tbb::blocked_range<size_t>(0, num_layers, grain_size),
1052             [this, &cache_top_botom_regions](const tbb::blocked_range<size_t>& range) {
1053                 const SurfaceType surfaces_bottom[2] = { stBottom, stBottomBridge };
1054                 const size_t num_regions = this->region_volumes.size();
1055                 for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) {
1056                     m_print->throw_if_canceled();
1057                     const Layer                      &layer = *m_layers[idx_layer];
1058                     DiscoverVerticalShellsCacheEntry &cache = cache_top_botom_regions[idx_layer];
1059                     // Simulate single set of perimeters over all merged regions.
1060                     float                             perimeter_offset = 0.f;
1061                     float                             perimeter_min_spacing = FLT_MAX;
1062 #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
1063                     static size_t debug_idx = 0;
1064                     ++ debug_idx;
1065 #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
1066                     for (size_t idx_region = 0; idx_region < num_regions; ++ idx_region) {
1067                         LayerRegion &layerm                       = *layer.m_regions[idx_region];
1068                         float        min_perimeter_infill_spacing = float(layerm.flow(frSolidInfill).scaled_spacing()) * 1.05f;
1069                         // Top surfaces.
1070                         append(cache.top_surfaces, offset(to_expolygons(layerm.slices.filter_by_type(stTop)), min_perimeter_infill_spacing));
1071                         append(cache.top_surfaces, offset(to_expolygons(layerm.fill_surfaces.filter_by_type(stTop)), min_perimeter_infill_spacing));
1072                         // Bottom surfaces.
1073                         append(cache.bottom_surfaces, offset(to_expolygons(layerm.slices.filter_by_types(surfaces_bottom, 2)), min_perimeter_infill_spacing));
1074                         append(cache.bottom_surfaces, offset(to_expolygons(layerm.fill_surfaces.filter_by_types(surfaces_bottom, 2)), min_perimeter_infill_spacing));
1075                         // Calculate the maximum perimeter offset as if the slice was extruded with a single extruder only.
1076                         // First find the maxium number of perimeters per region slice.
1077                         unsigned int perimeters = 0;
1078                         for (Surface &s : layerm.slices.surfaces)
1079                             perimeters = std::max<unsigned int>(perimeters, s.extra_perimeters);
1080                         perimeters += layerm.region()->config().perimeters.value;
1081                         // Then calculate the infill offset.
1082                         if (perimeters > 0) {
1083                             Flow extflow = layerm.flow(frExternalPerimeter);
1084                             Flow flow    = layerm.flow(frPerimeter);
1085                             perimeter_offset = std::max(perimeter_offset,
1086                                 0.5f * float(extflow.scaled_width() + extflow.scaled_spacing()) + (float(perimeters) - 1.f) * flow.scaled_spacing());
1087                             perimeter_min_spacing = std::min(perimeter_min_spacing, float(std::min(extflow.scaled_spacing(), flow.scaled_spacing())));
1088                         }
1089                         polygons_append(cache.holes, to_polygons(layerm.fill_expolygons));
1090                     }
1091                     // Save some computing time by reducing the number of polygons.
1092                     cache.top_surfaces    = union_(cache.top_surfaces,    false);
1093                     cache.bottom_surfaces = union_(cache.bottom_surfaces, false);
1094                     // For a multi-material print, simulate perimeter / infill split as if only a single extruder has been used for the whole print.
1095                     if (perimeter_offset > 0.) {
1096                         // The layer.lslices are forced to merge by expanding them first.
1097                         polygons_append(cache.holes, offset(offset_ex(layer.lslices, 0.3f * perimeter_min_spacing), - perimeter_offset - 0.3f * perimeter_min_spacing));
1098 #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
1099                         {
1100                             Slic3r::SVG svg(debug_out_path("discover_vertical_shells-extra-holes-%d.svg", debug_idx), get_extents(layer.lslices));
1101                             svg.draw(layer.lslices, "blue");
1102                             svg.draw(union_ex(cache.holes), "red");
1103                             svg.draw_outline(union_ex(cache.holes), "black", "blue", scale_(0.05));
1104                             svg.Close();
1105                         }
1106 #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
1107                     }
1108                     cache.holes = union_(cache.holes, false);
1109                 }
1110             });
1111         m_print->throw_if_canceled();
1112         BOOST_LOG_TRIVIAL(debug) << "Discovering vertical shells in parallel - end : cache top / bottom";
1113     }
1114 
1115     for (size_t idx_region = 0; idx_region < this->region_volumes.size(); ++ idx_region) {
1116         PROFILE_BLOCK(discover_vertical_shells_region);
1117 
1118         const PrintRegion &region = *m_print->get_region(idx_region);
1119         if (! region.config().ensure_vertical_shell_thickness.value)
1120             // This region will be handled by discover_horizontal_shells().
1121             continue;
1122         if (! has_extra_layers_fn(region.config()))
1123             // Zero or 1 layer, there is no additional vertical wall thickness enforced.
1124             continue;
1125 
1126         //FIXME Improve the heuristics for a grain size.
1127         size_t grain_size = std::max(num_layers / 16, size_t(1));
1128 
1129         if (! top_bottom_surfaces_all_regions) {
1130             // This is either a single material print, or a multi-material print and interface_shells are enabled, meaning that the vertical shell thickness
1131             // is calculated over a single material.
1132             BOOST_LOG_TRIVIAL(debug) << "Discovering vertical shells for region " << idx_region << " in parallel - start : cache top / bottom";
1133             tbb::parallel_for(
1134                 tbb::blocked_range<size_t>(0, num_layers, grain_size),
1135                 [this, idx_region, &cache_top_botom_regions](const tbb::blocked_range<size_t>& range) {
1136                     const SurfaceType surfaces_bottom[2] = { stBottom, stBottomBridge };
1137                     for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) {
1138                         m_print->throw_if_canceled();
1139                         Layer       &layer                        = *m_layers[idx_layer];
1140                         LayerRegion &layerm                       = *layer.m_regions[idx_region];
1141                         float        min_perimeter_infill_spacing = float(layerm.flow(frSolidInfill).scaled_spacing()) * 1.05f;
1142                         // Top surfaces.
1143                         auto &cache = cache_top_botom_regions[idx_layer];
1144                         cache.top_surfaces = offset(to_expolygons(layerm.slices.filter_by_type(stTop)), min_perimeter_infill_spacing);
1145                         append(cache.top_surfaces, offset(to_expolygons(layerm.fill_surfaces.filter_by_type(stTop)), min_perimeter_infill_spacing));
1146                         // Bottom surfaces.
1147                         cache.bottom_surfaces = offset(to_expolygons(layerm.slices.filter_by_types(surfaces_bottom, 2)), min_perimeter_infill_spacing);
1148                         append(cache.bottom_surfaces, offset(to_expolygons(layerm.fill_surfaces.filter_by_types(surfaces_bottom, 2)), min_perimeter_infill_spacing));
1149                         // Holes over all regions. Only collect them once, they are valid for all idx_region iterations.
1150                         if (cache.holes.empty()) {
1151                             for (size_t idx_region = 0; idx_region < layer.regions().size(); ++ idx_region)
1152                                 polygons_append(cache.holes, to_polygons(layer.regions()[idx_region]->fill_expolygons));
1153                         }
1154                     }
1155                 });
1156             m_print->throw_if_canceled();
1157             BOOST_LOG_TRIVIAL(debug) << "Discovering vertical shells for region " << idx_region << " in parallel - end : cache top / bottom";
1158         }
1159 
1160         BOOST_LOG_TRIVIAL(debug) << "Discovering vertical shells for region " << idx_region << " in parallel - start : ensure vertical wall thickness";
1161         tbb::parallel_for(
1162             tbb::blocked_range<size_t>(0, num_layers, grain_size),
1163             [this, idx_region, &cache_top_botom_regions]
1164             (const tbb::blocked_range<size_t>& range) {
1165                 // printf("discover_vertical_shells from %d to %d\n", range.begin(), range.end());
1166                 for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) {
1167                     PROFILE_BLOCK(discover_vertical_shells_region_layer);
1168                     m_print->throw_if_canceled();
1169 #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
1170         			static size_t debug_idx = 0;
1171         			++ debug_idx;
1172 #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
1173 
1174                     Layer       	        *layer          = m_layers[idx_layer];
1175                     LayerRegion 	        *layerm         = layer->m_regions[idx_region];
1176                     const PrintRegionConfig &region_config  = layerm->region()->config();
1177 
1178 #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
1179                     layerm->export_region_slices_to_svg_debug("4_discover_vertical_shells-initial");
1180                     layerm->export_region_fill_surfaces_to_svg_debug("4_discover_vertical_shells-initial");
1181 #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
1182 
1183                     Flow         solid_infill_flow   = layerm->flow(frSolidInfill);
1184                     coord_t      infill_line_spacing = solid_infill_flow.scaled_spacing();
1185                     // Find a union of perimeters below / above this surface to guarantee a minimum shell thickness.
1186                     Polygons shell;
1187                     Polygons holes;
1188 #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
1189                     ExPolygons shell_ex;
1190 #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
1191                     float min_perimeter_infill_spacing = float(infill_line_spacing) * 1.05f;
1192                     {
1193                         PROFILE_BLOCK(discover_vertical_shells_region_layer_collect);
1194 #if 0
1195 // #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
1196                         {
1197         					Slic3r::SVG svg_cummulative(debug_out_path("discover_vertical_shells-perimeters-before-union-run%d.svg", debug_idx), this->bounding_box());
1198                             for (int n = (int)idx_layer - n_extra_bottom_layers; n <= (int)idx_layer + n_extra_top_layers; ++ n) {
1199                                 if (n < 0 || n >= (int)m_layers.size())
1200                                     continue;
1201                                 ExPolygons &expolys = m_layers[n]->perimeter_expolygons;
1202                                 for (size_t i = 0; i < expolys.size(); ++ i) {
1203         							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]));
1204                                     svg.draw(expolys[i]);
1205                                     svg.draw_outline(expolys[i].contour, "black", scale_(0.05));
1206                                     svg.draw_outline(expolys[i].holes, "blue", scale_(0.05));
1207                                     svg.Close();
1208 
1209                                     svg_cummulative.draw(expolys[i]);
1210                                     svg_cummulative.draw_outline(expolys[i].contour, "black", scale_(0.05));
1211                                     svg_cummulative.draw_outline(expolys[i].holes, "blue", scale_(0.05));
1212                                 }
1213                             }
1214                         }
1215 #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
1216 			        	polygons_append(holes, cache_top_botom_regions[idx_layer].holes);
1217 			        	if (int n_top_layers = region_config.top_solid_layers.value; n_top_layers > 0) {
1218                             // Gather top regions projected to this layer.
1219                             coordf_t print_z = layer->print_z;
1220 	                        for (int i = int(idx_layer) + 1;
1221 	                        	i < int(cache_top_botom_regions.size()) &&
1222 	                        		(i < int(idx_layer) + n_top_layers ||
1223 	                        		 m_layers[i]->print_z - print_z < region_config.top_solid_min_thickness - EPSILON);
1224 	                        	++ i) {
1225 	                            const DiscoverVerticalShellsCacheEntry &cache = cache_top_botom_regions[i];
1226 								if (! holes.empty())
1227 									holes = intersection(holes, cache.holes);
1228 								if (! cache.top_surfaces.empty()) {
1229 		                            polygons_append(shell, cache.top_surfaces);
1230 		                            // Running the union_ using the Clipper library piece by piece is cheaper
1231 		                            // than running the union_ all at once.
1232 	                               shell = union_(shell, false);
1233 	                           }
1234 	                        }
1235 	                    }
1236 	                    if (int n_bottom_layers = region_config.bottom_solid_layers.value; n_bottom_layers > 0) {
1237                             // Gather bottom regions projected to this layer.
1238                             coordf_t bottom_z = layer->bottom_z();
1239 	                        for (int i = int(idx_layer) - 1;
1240 	                        	i >= 0 &&
1241 	                        		(i > int(idx_layer) - n_bottom_layers ||
1242 	                        		 bottom_z - m_layers[i]->bottom_z() < region_config.bottom_solid_min_thickness - EPSILON);
1243 	                        	-- i) {
1244 	                            const DiscoverVerticalShellsCacheEntry &cache = cache_top_botom_regions[i];
1245 								if (! holes.empty())
1246 									holes = intersection(holes, cache.holes);
1247 								if (! cache.bottom_surfaces.empty()) {
1248 		                            polygons_append(shell, cache.bottom_surfaces);
1249 		                            // Running the union_ using the Clipper library piece by piece is cheaper
1250 		                            // than running the union_ all at once.
1251 		                            shell = union_(shell, false);
1252 		                        }
1253 	                        }
1254 	                    }
1255 #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
1256                         {
1257         					Slic3r::SVG svg(debug_out_path("discover_vertical_shells-perimeters-before-union-%d.svg", debug_idx), get_extents(shell));
1258                             svg.draw(shell);
1259                             svg.draw_outline(shell, "black", scale_(0.05));
1260                             svg.Close();
1261                         }
1262 #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
1263 #if 0
1264                         {
1265                             PROFILE_BLOCK(discover_vertical_shells_region_layer_shell_);
1266         //                    shell = union_(shell, true);
1267                             shell = union_(shell, false);
1268                         }
1269 #endif
1270 #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
1271                         shell_ex = union_ex(shell, true);
1272 #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
1273                     }
1274 
1275                     //if (shell.empty())
1276                     //    continue;
1277 
1278 #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
1279                     {
1280                         Slic3r::SVG svg(debug_out_path("discover_vertical_shells-perimeters-after-union-%d.svg", debug_idx), get_extents(shell));
1281                         svg.draw(shell_ex);
1282                         svg.draw_outline(shell_ex, "black", "blue", scale_(0.05));
1283                         svg.Close();
1284                     }
1285 #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
1286 
1287 #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
1288                     {
1289                         Slic3r::SVG svg(debug_out_path("discover_vertical_shells-internal-wshell-%d.svg", debug_idx), get_extents(shell));
1290                         svg.draw(layerm->fill_surfaces.filter_by_type(stInternal), "yellow", 0.5);
1291                         svg.draw_outline(layerm->fill_surfaces.filter_by_type(stInternal), "black", "blue", scale_(0.05));
1292                         svg.draw(shell_ex, "blue", 0.5);
1293                         svg.draw_outline(shell_ex, "black", "blue", scale_(0.05));
1294                         svg.Close();
1295                     }
1296                     {
1297                         Slic3r::SVG svg(debug_out_path("discover_vertical_shells-internalvoid-wshell-%d.svg", debug_idx), get_extents(shell));
1298                         svg.draw(layerm->fill_surfaces.filter_by_type(stInternalVoid), "yellow", 0.5);
1299                         svg.draw_outline(layerm->fill_surfaces.filter_by_type(stInternalVoid), "black", "blue", scale_(0.05));
1300                         svg.draw(shell_ex, "blue", 0.5);
1301                         svg.draw_outline(shell_ex, "black", "blue", scale_(0.05));
1302                         svg.Close();
1303                     }
1304                     {
1305                         Slic3r::SVG svg(debug_out_path("discover_vertical_shells-internalvoid-wshell-%d.svg", debug_idx), get_extents(shell));
1306                         svg.draw(layerm->fill_surfaces.filter_by_type(stInternalVoid), "yellow", 0.5);
1307                         svg.draw_outline(layerm->fill_surfaces.filter_by_type(stInternalVoid), "black", "blue", scale_(0.05));
1308                         svg.draw(shell_ex, "blue", 0.5);
1309                         svg.draw_outline(shell_ex, "black", "blue", scale_(0.05));
1310                         svg.Close();
1311                     }
1312 #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
1313 
1314                     // Trim the shells region by the internal & internal void surfaces.
1315                     const SurfaceType surfaceTypesInternal[] = { stInternal, stInternalVoid, stInternalSolid };
1316                     const Polygons    polygonsInternal = to_polygons(layerm->fill_surfaces.filter_by_types(surfaceTypesInternal, 3));
1317                     shell = intersection(shell, polygonsInternal, true);
1318                     polygons_append(shell, diff(polygonsInternal, holes));
1319                     if (shell.empty())
1320                         continue;
1321 
1322                     // Append the internal solids, so they will be merged with the new ones.
1323                     polygons_append(shell, to_polygons(layerm->fill_surfaces.filter_by_type(stInternalSolid)));
1324 
1325                     // These regions will be filled by a rectilinear full infill. Currently this type of infill
1326                     // only fills regions, which fit at least a single line. To avoid gaps in the sparse infill,
1327                     // make sure that this region does not contain parts narrower than the infill spacing width.
1328 #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
1329                     Polygons shell_before = shell;
1330 #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
1331 #if 1
1332                     // Intentionally inflate a bit more than how much the region has been shrunk,
1333                     // so there will be some overlap between this solid infill and the other infill regions (mainly the sparse infill).
1334                     shell = offset(offset_ex(union_ex(shell), - 0.5f * min_perimeter_infill_spacing), 0.8f * min_perimeter_infill_spacing, ClipperLib::jtSquare);
1335                     if (shell.empty())
1336                         continue;
1337 #else
1338                     // Ensure each region is at least 3x infill line width wide, so it could be filled in.
1339         //            float margin = float(infill_line_spacing) * 3.f;
1340                     float margin = float(infill_line_spacing) * 1.5f;
1341                     // we use a higher miterLimit here to handle areas with acute angles
1342                     // in those cases, the default miterLimit would cut the corner and we'd
1343                     // get a triangle in $too_narrow; if we grow it below then the shell
1344                     // would have a different shape from the external surface and we'd still
1345                     // have the same angle, so the next shell would be grown even more and so on.
1346                     Polygons too_narrow = diff(shell, offset2(shell, -margin, margin, ClipperLib::jtMiter, 5.), true);
1347                     if (! too_narrow.empty()) {
1348                         // grow the collapsing parts and add the extra area to  the neighbor layer
1349                         // as well as to our original surfaces so that we support this
1350                         // additional area in the next shell too
1351                         // make sure our grown surfaces don't exceed the fill area
1352                         polygons_append(shell, intersection(offset(too_narrow, margin), polygonsInternal));
1353                     }
1354 #endif
1355                     ExPolygons new_internal_solid = intersection_ex(polygonsInternal, shell, false);
1356 #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
1357                     {
1358                         Slic3r::SVG svg(debug_out_path("discover_vertical_shells-regularized-%d.svg", debug_idx), get_extents(shell_before));
1359                         // Source shell.
1360                         svg.draw(union_ex(shell_before, true));
1361                         // Shell trimmed to the internal surfaces.
1362                         svg.draw_outline(union_ex(shell, true), "black", "blue", scale_(0.05));
1363                         // Regularized infill region.
1364                         svg.draw_outline(new_internal_solid, "red", "magenta", scale_(0.05));
1365                         svg.Close();
1366                     }
1367 #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
1368 
1369                     // Trim the internal & internalvoid by the shell.
1370                     Slic3r::ExPolygons new_internal = diff_ex(
1371                         to_polygons(layerm->fill_surfaces.filter_by_type(stInternal)),
1372                         shell,
1373                         false
1374                     );
1375                     Slic3r::ExPolygons new_internal_void = diff_ex(
1376                         to_polygons(layerm->fill_surfaces.filter_by_type(stInternalVoid)),
1377                         shell,
1378                         false
1379                     );
1380 
1381 #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
1382                     {
1383                         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));
1384         				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));
1385         				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));
1386                     }
1387 #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
1388 
1389                     // Assign resulting internal surfaces to layer.
1390                     const SurfaceType surfaceTypesKeep[] = { stTop, stBottom, stBottomBridge };
1391                     layerm->fill_surfaces.keep_types(surfaceTypesKeep, sizeof(surfaceTypesKeep)/sizeof(SurfaceType));
1392                     layerm->fill_surfaces.append(new_internal,       stInternal);
1393                     layerm->fill_surfaces.append(new_internal_void,  stInternalVoid);
1394                     layerm->fill_surfaces.append(new_internal_solid, stInternalSolid);
1395                 } // for each layer
1396             });
1397         m_print->throw_if_canceled();
1398         BOOST_LOG_TRIVIAL(debug) << "Discovering vertical shells for region " << idx_region << " in parallel - end";
1399 
1400 #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
1401 		for (size_t idx_layer = 0; idx_layer < m_layers.size(); ++idx_layer) {
1402 			LayerRegion *layerm = m_layers[idx_layer]->get_region(idx_region);
1403 			layerm->export_region_slices_to_svg_debug("4_discover_vertical_shells-final");
1404 			layerm->export_region_fill_surfaces_to_svg_debug("4_discover_vertical_shells-final");
1405 		}
1406 #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
1407     } // for each region
1408 
1409     // Write the profiler measurements to file
1410 //    PROFILE_UPDATE();
1411 //    PROFILE_OUTPUT(debug_out_path("discover_vertical_shells-profile.txt").c_str());
1412 }
1413 
1414 /* This method applies bridge flow to the first internal solid layer above
1415    sparse infill */
bridge_over_infill()1416 void PrintObject::bridge_over_infill()
1417 {
1418     BOOST_LOG_TRIVIAL(info) << "Bridge over infill..." << log_memory_info();
1419 
1420     for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) {
1421         const PrintRegion &region = *m_print->regions()[region_id];
1422 
1423         // skip bridging in case there are no voids
1424         if (region.config().fill_density.value == 100) continue;
1425 
1426         // get bridge flow
1427         Flow bridge_flow = region.flow(
1428             frSolidInfill,
1429             -1,     // layer height, not relevant for bridge flow
1430             true,   // bridge
1431             false,  // first layer
1432             -1,     // custom width, not relevant for bridge flow
1433             *this
1434         );
1435 
1436 		for (LayerPtrs::iterator layer_it = m_layers.begin(); layer_it != m_layers.end(); ++ layer_it) {
1437             // skip first layer
1438 			if (layer_it == m_layers.begin())
1439                 continue;
1440 
1441             Layer* layer        = *layer_it;
1442             LayerRegion* layerm = layer->m_regions[region_id];
1443 
1444             // extract the stInternalSolid surfaces that might be transformed into bridges
1445             Polygons internal_solid;
1446             layerm->fill_surfaces.filter_by_type(stInternalSolid, &internal_solid);
1447 
1448             // check whether the lower area is deep enough for absorbing the extra flow
1449             // (for obvious physical reasons but also for preventing the bridge extrudates
1450             // from overflowing in 3D preview)
1451             ExPolygons to_bridge;
1452             {
1453                 Polygons to_bridge_pp = internal_solid;
1454 
1455                 // iterate through lower layers spanned by bridge_flow
1456                 double bottom_z = layer->print_z - bridge_flow.height;
1457                 for (int i = int(layer_it - m_layers.begin()) - 1; i >= 0; --i) {
1458                     const Layer* lower_layer = m_layers[i];
1459 
1460                     // stop iterating if layer is lower than bottom_z
1461                     if (lower_layer->print_z < bottom_z) break;
1462 
1463                     // iterate through regions and collect internal surfaces
1464                     Polygons lower_internal;
1465                     for (LayerRegion *lower_layerm : lower_layer->m_regions)
1466                         lower_layerm->fill_surfaces.filter_by_type(stInternal, &lower_internal);
1467 
1468                     // intersect such lower internal surfaces with the candidate solid surfaces
1469                     to_bridge_pp = intersection(to_bridge_pp, lower_internal);
1470                 }
1471 
1472                 // there's no point in bridging too thin/short regions
1473                 //FIXME Vojtech: The offset2 function is not a geometric offset,
1474                 // therefore it may create 1) gaps, and 2) sharp corners, which are outside the original contour.
1475                 // The gaps will be filled by a separate region, which makes the infill less stable and it takes longer.
1476                 {
1477                     float min_width = float(bridge_flow.scaled_width()) * 3.f;
1478                     to_bridge_pp = offset2(to_bridge_pp, -min_width, +min_width);
1479                 }
1480 
1481                 if (to_bridge_pp.empty()) continue;
1482 
1483                 // convert into ExPolygons
1484                 to_bridge = union_ex(to_bridge_pp);
1485             }
1486 
1487             #ifdef SLIC3R_DEBUG
1488             printf("Bridging %zu internal areas at layer %zu\n", to_bridge.size(), layer->id());
1489             #endif
1490 
1491             // compute the remaning internal solid surfaces as difference
1492             ExPolygons not_to_bridge = diff_ex(internal_solid, to_polygons(to_bridge), true);
1493             to_bridge = intersection_ex(to_polygons(to_bridge), internal_solid, true);
1494             // build the new collection of fill_surfaces
1495             layerm->fill_surfaces.remove_type(stInternalSolid);
1496             for (ExPolygon &ex : to_bridge)
1497                 layerm->fill_surfaces.surfaces.push_back(Surface(stInternalBridge, ex));
1498             for (ExPolygon &ex : not_to_bridge)
1499                 layerm->fill_surfaces.surfaces.push_back(Surface(stInternalSolid, ex));
1500             /*
1501             # exclude infill from the layers below if needed
1502             # see discussion at https://github.com/alexrj/Slic3r/issues/240
1503             # Update: do not exclude any infill. Sparse infill is able to absorb the excess material.
1504             if (0) {
1505                 my $excess = $layerm->extruders->{infill}->bridge_flow->width - $layerm->height;
1506                 for (my $i = $layer_id-1; $excess >= $self->get_layer($i)->height; $i--) {
1507                     Slic3r::debugf "  skipping infill below those areas at layer %d\n", $i;
1508                     foreach my $lower_layerm (@{$self->get_layer($i)->regions}) {
1509                         my @new_surfaces = ();
1510                         # subtract the area from all types of surfaces
1511                         foreach my $group (@{$lower_layerm->fill_surfaces->group}) {
1512                             push @new_surfaces, map $group->[0]->clone(expolygon => $_),
1513                                 @{diff_ex(
1514                                     [ map $_->p, @$group ],
1515                                     [ map @$_, @$to_bridge ],
1516                                 )};
1517                             push @new_surfaces, map Slic3r::Surface->new(
1518                                 expolygon       => $_,
1519                                 surface_type    => stInternalVoid,
1520                             ), @{intersection_ex(
1521                                 [ map $_->p, @$group ],
1522                                 [ map @$_, @$to_bridge ],
1523                             )};
1524                         }
1525                         $lower_layerm->fill_surfaces->clear;
1526                         $lower_layerm->fill_surfaces->append($_) for @new_surfaces;
1527                     }
1528 
1529                     $excess -= $self->get_layer($i)->height;
1530                 }
1531             }
1532             */
1533 
1534 #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
1535             layerm->export_region_slices_to_svg_debug("7_bridge_over_infill");
1536             layerm->export_region_fill_surfaces_to_svg_debug("7_bridge_over_infill");
1537 #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
1538             m_print->throw_if_canceled();
1539         }
1540     }
1541 }
1542 
clamp_exturder_to_default(ConfigOptionInt & opt,size_t num_extruders)1543 static void clamp_exturder_to_default(ConfigOptionInt &opt, size_t num_extruders)
1544 {
1545     if (opt.value > (int)num_extruders)
1546         // assign the default extruder
1547         opt.value = 1;
1548 }
1549 
object_config_from_model_object(const PrintObjectConfig & default_object_config,const ModelObject & object,size_t num_extruders)1550 PrintObjectConfig PrintObject::object_config_from_model_object(const PrintObjectConfig &default_object_config, const ModelObject &object, size_t num_extruders)
1551 {
1552     PrintObjectConfig config = default_object_config;
1553     {
1554         DynamicPrintConfig src_normalized(object.config.get());
1555         src_normalized.normalize_fdm();
1556         config.apply(src_normalized, true);
1557     }
1558     // Clamp invalid extruders to the default extruder (with index 1).
1559     clamp_exturder_to_default(config.support_material_extruder,           num_extruders);
1560     clamp_exturder_to_default(config.support_material_interface_extruder, num_extruders);
1561     return config;
1562 }
1563 
apply_to_print_region_config(PrintRegionConfig & out,const DynamicPrintConfig & in)1564 static void apply_to_print_region_config(PrintRegionConfig &out, const DynamicPrintConfig &in)
1565 {
1566     // 1) Copy the "extruder key to infill_extruder and perimeter_extruder.
1567     std::string sextruder = "extruder";
1568     auto *opt_extruder = in.opt<ConfigOptionInt>(sextruder);
1569     if (opt_extruder) {
1570         int extruder = opt_extruder->value;
1571         if (extruder != 0) {
1572             out.infill_extruder      .value = extruder;
1573             out.solid_infill_extruder.value = extruder;
1574             out.perimeter_extruder   .value = extruder;
1575         }
1576     }
1577     // 2) Copy the rest of the values.
1578     for (auto it = in.cbegin(); it != in.cend(); ++ it)
1579         if (it->first != sextruder) {
1580             ConfigOption *my_opt = out.option(it->first, false);
1581             if (my_opt)
1582                 my_opt->set(it->second.get());
1583         }
1584 }
1585 
region_config_from_model_volume(const PrintRegionConfig & default_region_config,const DynamicPrintConfig * layer_range_config,const ModelVolume & volume,size_t num_extruders)1586 PrintRegionConfig PrintObject::region_config_from_model_volume(const PrintRegionConfig &default_region_config, const DynamicPrintConfig *layer_range_config, const ModelVolume &volume, size_t num_extruders)
1587 {
1588     PrintRegionConfig config = default_region_config;
1589     apply_to_print_region_config(config, volume.get_object()->config.get());
1590     if (layer_range_config != nullptr)
1591     	apply_to_print_region_config(config, *layer_range_config);
1592     apply_to_print_region_config(config, volume.config.get());
1593     if (! volume.material_id().empty())
1594         apply_to_print_region_config(config, volume.material()->config.get());
1595     // Clamp invalid extruders to the default extruder (with index 1).
1596     clamp_exturder_to_default(config.infill_extruder,       num_extruders);
1597     clamp_exturder_to_default(config.perimeter_extruder,    num_extruders);
1598     clamp_exturder_to_default(config.solid_infill_extruder, num_extruders);
1599     return config;
1600 }
1601 
update_slicing_parameters()1602 void PrintObject::update_slicing_parameters()
1603 {
1604     if (! m_slicing_params.valid)
1605         m_slicing_params = SlicingParameters::create_from_config(
1606             this->print()->config(), m_config, unscale<double>(this->height()), this->object_extruders());
1607 }
1608 
slicing_parameters(const DynamicPrintConfig & full_config,const ModelObject & model_object,float object_max_z)1609 SlicingParameters PrintObject::slicing_parameters(const DynamicPrintConfig& full_config, const ModelObject& model_object, float object_max_z)
1610 {
1611 	PrintConfig         print_config;
1612 	PrintObjectConfig   object_config;
1613 	PrintRegionConfig   default_region_config;
1614 	print_config.apply(full_config, true);
1615 	object_config.apply(full_config, true);
1616 	default_region_config.apply(full_config, true);
1617 	size_t              num_extruders = print_config.nozzle_diameter.size();
1618 	object_config = object_config_from_model_object(object_config, model_object, num_extruders);
1619 
1620 	std::vector<unsigned int> object_extruders;
1621 	for (const ModelVolume* model_volume : model_object.volumes)
1622 		if (model_volume->is_model_part()) {
1623 			PrintRegion::collect_object_printing_extruders(
1624 				print_config,
1625 				region_config_from_model_volume(default_region_config, nullptr, *model_volume, num_extruders),
1626 				object_extruders);
1627 			for (const std::pair<const t_layer_height_range, ModelConfig> &range_and_config : model_object.layer_config_ranges)
1628 				if (range_and_config.second.has("perimeter_extruder") ||
1629 					range_and_config.second.has("infill_extruder") ||
1630 					range_and_config.second.has("solid_infill_extruder"))
1631 					PrintRegion::collect_object_printing_extruders(
1632 						print_config,
1633 						region_config_from_model_volume(default_region_config, &range_and_config.second.get(), *model_volume, num_extruders),
1634 						object_extruders);
1635 		}
1636     sort_remove_duplicates(object_extruders);
1637 
1638     if (object_max_z <= 0.f)
1639         object_max_z = (float)model_object.raw_bounding_box().size().z();
1640     return SlicingParameters::create_from_config(print_config, object_config, object_max_z, object_extruders);
1641 }
1642 
1643 // returns 0-based indices of extruders used to print the object (without brim, support and other helper extrusions)
object_extruders() const1644 std::vector<unsigned int> PrintObject::object_extruders() const
1645 {
1646     std::vector<unsigned int> extruders;
1647     extruders.reserve(this->region_volumes.size() * 3);
1648     for (size_t idx_region = 0; idx_region < this->region_volumes.size(); ++ idx_region)
1649         if (! this->region_volumes[idx_region].empty())
1650             m_print->get_region(idx_region)->collect_object_printing_extruders(extruders);
1651     sort_remove_duplicates(extruders);
1652     return extruders;
1653 }
1654 
update_layer_height_profile(const ModelObject & model_object,const SlicingParameters & slicing_parameters,std::vector<coordf_t> & layer_height_profile)1655 bool PrintObject::update_layer_height_profile(const ModelObject &model_object, const SlicingParameters &slicing_parameters, std::vector<coordf_t> &layer_height_profile)
1656 {
1657     bool updated = false;
1658 
1659     if (layer_height_profile.empty()) {
1660         // use the constructor because the assignement is crashing on ASAN OsX
1661         layer_height_profile = std::vector<coordf_t>(model_object.layer_height_profile.get());
1662 //        layer_height_profile = model_object.layer_height_profile;
1663         updated = true;
1664     }
1665 
1666     // Verify the layer_height_profile.
1667     if (! layer_height_profile.empty() &&
1668             // Must not be of even length.
1669             ((layer_height_profile.size() & 1) != 0 ||
1670             // Last entry must be at the top of the object.
1671              std::abs(layer_height_profile[layer_height_profile.size() - 2] - slicing_parameters.object_print_z_height()) > 1e-3))
1672         layer_height_profile.clear();
1673 
1674     if (layer_height_profile.empty()) {
1675         //layer_height_profile = layer_height_profile_adaptive(slicing_parameters, model_object.layer_config_ranges, model_object.volumes);
1676         layer_height_profile = layer_height_profile_from_ranges(slicing_parameters, model_object.layer_config_ranges);
1677         updated = true;
1678     }
1679     return updated;
1680 }
1681 
1682 // 1) Decides Z positions of the layers,
1683 // 2) Initializes layers and their regions
1684 // 3) Slices the object meshes
1685 // 4) Slices the modifier meshes and reclassifies the slices of the object meshes by the slices of the modifier meshes
1686 // 5) Applies size compensation (offsets the slices in XY plane)
1687 // 6) Replaces bad slices by the slices reconstructed from the upper/lower layer
1688 // Resulting expolygons of layer regions are marked as Internal.
1689 //
1690 // this should be idempotent
_slice(const std::vector<coordf_t> & layer_height_profile)1691 void PrintObject::_slice(const std::vector<coordf_t> &layer_height_profile)
1692 {
1693     BOOST_LOG_TRIVIAL(info) << "Slicing objects..." << log_memory_info();
1694 
1695     m_typed_slices = false;
1696 
1697     // 1) Initialize layers and their slice heights.
1698     std::vector<float> slice_zs;
1699     {
1700         this->clear_layers();
1701         // Object layers (pairs of bottom/top Z coordinate), without the raft.
1702         std::vector<coordf_t> object_layers = generate_object_layers(m_slicing_params, layer_height_profile);
1703         // Reserve object layers for the raft. Last layer of the raft is the contact layer.
1704         int id = int(m_slicing_params.raft_layers());
1705         slice_zs.reserve(object_layers.size());
1706         Layer *prev = nullptr;
1707         for (size_t i_layer = 0; i_layer < object_layers.size(); i_layer += 2) {
1708             coordf_t lo = object_layers[i_layer];
1709             coordf_t hi = object_layers[i_layer + 1];
1710             coordf_t slice_z = 0.5 * (lo + hi);
1711             Layer *layer = this->add_layer(id ++, hi - lo, hi + m_slicing_params.object_print_z_min, slice_z);
1712             slice_zs.push_back(float(slice_z));
1713             if (prev != nullptr) {
1714                 prev->upper_layer = layer;
1715                 layer->lower_layer = prev;
1716             }
1717             // Make sure all layers contain layer region objects for all regions.
1718             for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id)
1719                 layer->add_region(this->print()->regions()[region_id]);
1720             prev = layer;
1721         }
1722     }
1723 
1724     // Count model parts and modifier meshes, check whether the model parts are of the same region.
1725     int              all_volumes_single_region = -2; // not set yet
1726     bool 			 has_z_ranges  = false;
1727 	size_t           num_volumes   = 0;
1728     size_t           num_modifiers = 0;
1729     for (int region_id = 0; region_id < (int)this->region_volumes.size(); ++ region_id) {
1730 		int last_volume_id = -1;
1731         for (const std::pair<t_layer_height_range, int> &volume_and_range : this->region_volumes[region_id]) {
1732 			const int		   volume_id    = volume_and_range.second;
1733 			const ModelVolume *model_volume = this->model_object()->volumes[volume_id];
1734             if (model_volume->is_model_part()) {
1735 				if (last_volume_id == volume_id) {
1736 					has_z_ranges = true;
1737 				} else {
1738 					last_volume_id = volume_id;
1739 					if (all_volumes_single_region == -2)
1740 						// first model volume met
1741 						all_volumes_single_region = region_id;
1742 					else if (all_volumes_single_region != region_id)
1743 						// multiple volumes met and they are not equal
1744 						all_volumes_single_region = -1;
1745 					++ num_volumes;
1746 				}
1747             } else if (model_volume->is_modifier())
1748                 ++ num_modifiers;
1749         }
1750     }
1751     assert(num_volumes > 0);
1752 
1753     // Slice all non-modifier volumes.
1754     bool clipped  = false;
1755     bool upscaled = false;
1756     bool spiral_vase  = this->print()->config().spiral_vase;
1757     auto slicing_mode = spiral_vase ? SlicingMode::PositiveLargestContour : SlicingMode::Regular;
1758     if (! has_z_ranges && (! m_config.clip_multipart_objects.value || all_volumes_single_region >= 0)) {
1759         // Cheap path: Slice regions without mutual clipping.
1760         // The cheap path is possible if no clipping is allowed or if slicing volumes of just a single region.
1761         for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) {
1762             BOOST_LOG_TRIVIAL(debug) << "Slicing objects - region " << region_id;
1763             // slicing in parallel
1764             size_t slicing_mode_normal_below_layer = 0;
1765             if (spiral_vase) {
1766                 // Slice the bottom layers with SlicingMode::Regular.
1767                 // This needs to be in sync with LayerRegion::make_perimeters() spiral_vase!
1768                 const PrintRegionConfig &config = this->print()->regions()[region_id]->config();
1769                 slicing_mode_normal_below_layer = size_t(config.bottom_solid_layers.value);
1770                 for (; slicing_mode_normal_below_layer < slice_zs.size() && slice_zs[slicing_mode_normal_below_layer] < config.bottom_solid_min_thickness - EPSILON;
1771                     ++ slicing_mode_normal_below_layer);
1772             }
1773             std::vector<ExPolygons> expolygons_by_layer = this->slice_region(region_id, slice_zs, slicing_mode, slicing_mode_normal_below_layer, SlicingMode::Regular);
1774             m_print->throw_if_canceled();
1775             BOOST_LOG_TRIVIAL(debug) << "Slicing objects - append slices " << region_id << " start";
1776             for (size_t layer_id = 0; layer_id < expolygons_by_layer.size(); ++ layer_id)
1777                 m_layers[layer_id]->regions()[region_id]->slices.append(std::move(expolygons_by_layer[layer_id]), stInternal);
1778             m_print->throw_if_canceled();
1779             BOOST_LOG_TRIVIAL(debug) << "Slicing objects - append slices " << region_id << " end";
1780         }
1781     } else {
1782         // Expensive path: Slice one volume after the other in the order they are presented at the user interface,
1783         // clip the last volumes with the first.
1784         // First slice the volumes.
1785         struct SlicedVolume {
1786             SlicedVolume(int volume_id, int region_id, std::vector<ExPolygons> &&expolygons_by_layer) :
1787                 volume_id(volume_id), region_id(region_id), expolygons_by_layer(std::move(expolygons_by_layer)) {}
1788             int                     volume_id;
1789             int                     region_id;
1790             std::vector<ExPolygons> expolygons_by_layer;
1791         };
1792         std::vector<SlicedVolume> sliced_volumes;
1793         sliced_volumes.reserve(num_volumes);
1794 		for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) {
1795 			const std::vector<std::pair<t_layer_height_range, int>> &volumes_and_ranges = this->region_volumes[region_id];
1796 			for (size_t i = 0; i < volumes_and_ranges.size(); ) {
1797 				int 			   volume_id    = volumes_and_ranges[i].second;
1798 				const ModelVolume *model_volume = this->model_object()->volumes[volume_id];
1799 				if (model_volume->is_model_part()) {
1800 					BOOST_LOG_TRIVIAL(debug) << "Slicing objects - volume " << volume_id;
1801 					// Find the ranges of this volume. Ranges in volumes_and_ranges must not overlap for a single volume.
1802 					std::vector<t_layer_height_range> ranges;
1803 					ranges.emplace_back(volumes_and_ranges[i].first);
1804 					size_t j = i + 1;
1805 					for (; j < volumes_and_ranges.size() && volume_id == volumes_and_ranges[j].second; ++ j)
1806 						if (! ranges.empty() && std::abs(ranges.back().second - volumes_and_ranges[j].first.first) < EPSILON)
1807 							ranges.back().second = volumes_and_ranges[j].first.second;
1808 						else
1809 							ranges.emplace_back(volumes_and_ranges[j].first);
1810                     // slicing in parallel
1811 					sliced_volumes.emplace_back(volume_id, (int)region_id, this->slice_volume(slice_zs, ranges, slicing_mode, *model_volume));
1812 					i = j;
1813 				} else
1814 					++ i;
1815 			}
1816 		}
1817         // Second clip the volumes in the order they are presented at the user interface.
1818         BOOST_LOG_TRIVIAL(debug) << "Slicing objects - parallel clipping - start";
1819         tbb::parallel_for(
1820             tbb::blocked_range<size_t>(0, slice_zs.size()),
1821             [this, &sliced_volumes, num_modifiers](const tbb::blocked_range<size_t>& range) {
1822                 float delta   = float(scale_(m_config.xy_size_compensation.value));
1823                 // Only upscale together with clipping if there are no modifiers, as the modifiers shall be applied before upscaling
1824                 // (upscaling may grow the object outside of the modifier mesh).
1825                 bool  upscale = delta > 0 && num_modifiers == 0;
1826                 for (size_t layer_id = range.begin(); layer_id < range.end(); ++ layer_id) {
1827                     m_print->throw_if_canceled();
1828                     // Trim volumes in a single layer, one by the other, possibly apply upscaling.
1829                     {
1830                         Polygons processed;
1831                         for (SlicedVolume &sliced_volume : sliced_volumes)
1832                         	if (! sliced_volume.expolygons_by_layer.empty()) {
1833 	                            ExPolygons slices = std::move(sliced_volume.expolygons_by_layer[layer_id]);
1834 	                            if (upscale)
1835 	                                slices = offset_ex(std::move(slices), delta);
1836 	                            if (! processed.empty())
1837 	                                // Trim by the slices of already processed regions.
1838 	                                slices = diff_ex(to_polygons(std::move(slices)), processed);
1839 	                            if (size_t(&sliced_volume - &sliced_volumes.front()) + 1 < sliced_volumes.size())
1840 	                                // Collect the already processed regions to trim the to be processed regions.
1841 	                                polygons_append(processed, slices);
1842 	                            sliced_volume.expolygons_by_layer[layer_id] = std::move(slices);
1843 	                        }
1844                     }
1845                     // Collect and union volumes of a single region.
1846                     for (int region_id = 0; region_id < (int)this->region_volumes.size(); ++ region_id) {
1847                         ExPolygons expolygons;
1848                         size_t     num_volumes = 0;
1849                         for (SlicedVolume &sliced_volume : sliced_volumes)
1850                             if (sliced_volume.region_id == region_id && ! sliced_volume.expolygons_by_layer.empty() && ! sliced_volume.expolygons_by_layer[layer_id].empty()) {
1851                                 ++ num_volumes;
1852                                 append(expolygons, std::move(sliced_volume.expolygons_by_layer[layer_id]));
1853                             }
1854                         if (num_volumes > 1)
1855                             // Merge the islands using a positive / negative offset.
1856                             expolygons = offset_ex(offset_ex(expolygons, float(scale_(EPSILON))), -float(scale_(EPSILON)));
1857                         m_layers[layer_id]->regions()[region_id]->slices.append(std::move(expolygons), stInternal);
1858                     }
1859                 }
1860             });
1861         BOOST_LOG_TRIVIAL(debug) << "Slicing objects - parallel clipping - end";
1862         clipped  = true;
1863         upscaled = m_config.xy_size_compensation.value > 0 && num_modifiers == 0;
1864     }
1865 
1866     // Slice all modifier volumes.
1867     if (this->region_volumes.size() > 1) {
1868         for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) {
1869             BOOST_LOG_TRIVIAL(debug) << "Slicing modifier volumes - region " << region_id;
1870             // slicing in parallel
1871             std::vector<ExPolygons> expolygons_by_layer = this->slice_modifiers(region_id, slice_zs);
1872             m_print->throw_if_canceled();
1873             if (expolygons_by_layer.empty())
1874                 continue;
1875             // loop through the other regions and 'steal' the slices belonging to this one
1876             BOOST_LOG_TRIVIAL(debug) << "Slicing modifier volumes - stealing " << region_id << " start";
1877             tbb::parallel_for(
1878                 tbb::blocked_range<size_t>(0, m_layers.size()),
1879 				[this, &expolygons_by_layer, region_id](const tbb::blocked_range<size_t>& range) {
1880                     for (size_t layer_id = range.begin(); layer_id < range.end(); ++ layer_id) {
1881                         for (size_t other_region_id = 0; other_region_id < this->region_volumes.size(); ++ other_region_id) {
1882                             if (region_id == other_region_id)
1883                                 continue;
1884                             Layer       *layer = m_layers[layer_id];
1885                             LayerRegion *layerm = layer->m_regions[region_id];
1886                             LayerRegion *other_layerm = layer->m_regions[other_region_id];
1887                             if (layerm == nullptr || other_layerm == nullptr || other_layerm->slices.empty() || expolygons_by_layer[layer_id].empty())
1888                                 continue;
1889                             Polygons other_slices = to_polygons(other_layerm->slices);
1890                             ExPolygons my_parts = intersection_ex(other_slices, to_polygons(expolygons_by_layer[layer_id]));
1891                             if (my_parts.empty())
1892                                 continue;
1893                             // Remove such parts from original region.
1894                             other_layerm->slices.set(diff_ex(other_slices, to_polygons(my_parts)), stInternal);
1895                             // Append new parts to our region.
1896                             layerm->slices.append(std::move(my_parts), stInternal);
1897                         }
1898                     }
1899                 });
1900             m_print->throw_if_canceled();
1901             BOOST_LOG_TRIVIAL(debug) << "Slicing modifier volumes - stealing " << region_id << " end";
1902         }
1903     }
1904 
1905     BOOST_LOG_TRIVIAL(debug) << "Slicing objects - removing top empty layers";
1906     while (! m_layers.empty()) {
1907         const Layer *layer = m_layers.back();
1908         if (! layer->empty())
1909             goto end;
1910         delete layer;
1911         m_layers.pop_back();
1912 		if (! m_layers.empty())
1913 			m_layers.back()->upper_layer = nullptr;
1914     }
1915     m_print->throw_if_canceled();
1916 end:
1917     ;
1918 
1919     BOOST_LOG_TRIVIAL(debug) << "Slicing objects - make_slices in parallel - begin";
1920     {
1921         // Compensation value, scaled.
1922         const float xy_compensation_scaled 	 			= float(scale_(m_config.xy_size_compensation.value));
1923         const float elephant_foot_compensation_scaled 	= (m_config.raft_layers == 0) ?
1924         	// Only enable Elephant foot compensation if printing directly on the print bed.
1925             float(scale_(m_config.elefant_foot_compensation.value)) :
1926         	0.f;
1927         // Uncompensated slices for the first layer in case the Elephant foot compensation is applied.
1928 	    ExPolygons  lslices_1st_layer;
1929 	    tbb::parallel_for(
1930 	        tbb::blocked_range<size_t>(0, m_layers.size()),
1931 			[this, upscaled, clipped, xy_compensation_scaled, elephant_foot_compensation_scaled, &lslices_1st_layer]
1932 				(const tbb::blocked_range<size_t>& range) {
1933 	            for (size_t layer_id = range.begin(); layer_id < range.end(); ++ layer_id) {
1934 	                m_print->throw_if_canceled();
1935 	                Layer *layer = m_layers[layer_id];
1936 	                // Apply size compensation and perform clipping of multi-part objects.
1937 	                float elfoot = (layer_id == 0) ? elephant_foot_compensation_scaled : 0.f;
1938 	                if (layer->m_regions.size() == 1) {
1939 	                	assert(! upscaled);
1940 	                	assert(! clipped);
1941 	                    // Optimized version for a single region layer.
1942 	                    // Single region, growing or shrinking.
1943 	                    LayerRegion *layerm = layer->m_regions.front();
1944 	                    if (elfoot > 0) {
1945 		                    // Apply the elephant foot compensation and store the 1st layer slices without the Elephant foot compensation applied.
1946 		                    lslices_1st_layer = to_expolygons(std::move(layerm->slices.surfaces));
1947 		                    float delta = xy_compensation_scaled;
1948 	                        if (delta > elfoot) {
1949 	                            delta -= elfoot;
1950 	                            elfoot = 0.f;
1951 	                        } else if (delta > 0)
1952 	                            elfoot -= delta;
1953 							layerm->slices.set(
1954 								union_ex(
1955 									Slic3r::elephant_foot_compensation(
1956 										(delta == 0.f) ? lslices_1st_layer : offset_ex(lslices_1st_layer, delta),
1957 	                            		layerm->flow(frExternalPerimeter), unscale<double>(elfoot))),
1958 								stInternal);
1959 							if (xy_compensation_scaled != 0.f)
1960 								lslices_1st_layer = offset_ex(std::move(lslices_1st_layer), xy_compensation_scaled);
1961 	                    } else if (xy_compensation_scaled != 0.f) {
1962 	                        // Apply the XY compensation.
1963 	                        layerm->slices.set(
1964                                 offset_ex(to_expolygons(std::move(layerm->slices.surfaces)), xy_compensation_scaled),
1965 	                            stInternal);
1966 	                    }
1967 	                } else {
1968 	                    bool upscale   = ! upscaled && xy_compensation_scaled > 0.f;
1969 	                    bool clip      = ! clipped && m_config.clip_multipart_objects.value;
1970 	                    if (upscale || clip) {
1971 	                        // Multiple regions, growing or just clipping one region by the other.
1972 	                        // When clipping the regions, priority is given to the first regions.
1973 	                        Polygons processed;
1974 	            			for (size_t region_id = 0; region_id < layer->m_regions.size(); ++ region_id) {
1975 	                            LayerRegion *layerm = layer->m_regions[region_id];
1976 	            				ExPolygons slices = to_expolygons(std::move(layerm->slices.surfaces));
1977 	            				if (upscale)
1978 	            					slices = offset_ex(std::move(slices), xy_compensation_scaled);
1979 	                            if (region_id > 0 && clip)
1980 	                                // Trim by the slices of already processed regions.
1981 	                                slices = diff_ex(to_polygons(std::move(slices)), processed);
1982 	                            if (clip && (region_id + 1 < layer->m_regions.size()))
1983 	                                // Collect the already processed regions to trim the to be processed regions.
1984 	                                polygons_append(processed, slices);
1985 	                            layerm->slices.set(std::move(slices), stInternal);
1986 	                        }
1987 	                    }
1988 	                    if (xy_compensation_scaled < 0.f || elfoot > 0.f) {
1989 	                        // Apply the negative XY compensation.
1990 	                        Polygons trimming;
1991 	                        static const float eps = float(scale_(m_config.slice_closing_radius.value) * 1.5);
1992 	                        if (elfoot > 0.f) {
1993 	                        	lslices_1st_layer = offset_ex(layer->merged(eps), std::min(xy_compensation_scaled, 0.f) - eps);
1994 								trimming = to_polygons(Slic3r::elephant_foot_compensation(lslices_1st_layer,
1995 									layer->m_regions.front()->flow(frExternalPerimeter), unscale<double>(elfoot)));
1996 	                        } else
1997 		                        trimming = offset(layer->merged(float(SCALED_EPSILON)), xy_compensation_scaled - float(SCALED_EPSILON));
1998 	                        for (size_t region_id = 0; region_id < layer->m_regions.size(); ++ region_id)
1999 	                            layer->m_regions[region_id]->trim_surfaces(trimming);
2000 	                    }
2001 	                }
2002 	                // Merge all regions' slices to get islands, chain them by a shortest path.
2003 	                layer->make_slices();
2004 	            }
2005 	        });
2006 	    if (elephant_foot_compensation_scaled > 0.f && ! m_layers.empty()) {
2007 	    	// The Elephant foot has been compensated, therefore the 1st layer's lslices are shrank with the Elephant foot compensation value.
2008 	    	// Store the uncompensated value there.
2009 	    	assert(m_layers.front()->id() == 0);
2010 			m_layers.front()->lslices = std::move(lslices_1st_layer);
2011 		}
2012 	}
2013 
2014     m_print->throw_if_canceled();
2015     BOOST_LOG_TRIVIAL(debug) << "Slicing objects - make_slices in parallel - end";
2016 }
2017 
2018 // To be used only if there are no layer span specific configurations applied, which would lead to z ranges being generated for this region.
slice_region(size_t region_id,const std::vector<float> & z,SlicingMode mode,size_t slicing_mode_normal_below_layer,SlicingMode mode_below) const2019 std::vector<ExPolygons> PrintObject::slice_region(size_t region_id, const std::vector<float> &z, SlicingMode mode, size_t slicing_mode_normal_below_layer, SlicingMode mode_below) const
2020 {
2021 	std::vector<const ModelVolume*> volumes;
2022     if (region_id < this->region_volumes.size()) {
2023 		for (const std::pair<t_layer_height_range, int> &volume_and_range : this->region_volumes[region_id]) {
2024 			const ModelVolume *volume = this->model_object()->volumes[volume_and_range.second];
2025 			if (volume->is_model_part())
2026 				volumes.emplace_back(volume);
2027 		}
2028     }
2029 	return this->slice_volumes(z, mode, slicing_mode_normal_below_layer, mode_below, volumes);
2030 }
2031 
2032 // Z ranges are not applicable to modifier meshes, therefore a single volume will be found in volume_and_range at most once.
slice_modifiers(size_t region_id,const std::vector<float> & slice_zs) const2033 std::vector<ExPolygons> PrintObject::slice_modifiers(size_t region_id, const std::vector<float> &slice_zs) const
2034 {
2035 	std::vector<ExPolygons> out;
2036     if (region_id < this->region_volumes.size())
2037     {
2038 		std::vector<std::vector<t_layer_height_range>> volume_ranges;
2039 		const std::vector<std::pair<t_layer_height_range, int>> &volumes_and_ranges = this->region_volumes[region_id];
2040 		volume_ranges.reserve(volumes_and_ranges.size());
2041 		for (size_t i = 0; i < volumes_and_ranges.size(); ) {
2042 			int 			   volume_id    = volumes_and_ranges[i].second;
2043 			const ModelVolume *model_volume = this->model_object()->volumes[volume_id];
2044 			if (model_volume->is_modifier()) {
2045 				std::vector<t_layer_height_range> ranges;
2046 				ranges.emplace_back(volumes_and_ranges[i].first);
2047 				size_t j = i + 1;
2048 				for (; j < volumes_and_ranges.size() && volume_id == volumes_and_ranges[j].second; ++ j) {
2049 					if (! ranges.empty() && std::abs(ranges.back().second - volumes_and_ranges[j].first.first) < EPSILON)
2050 						ranges.back().second = volumes_and_ranges[j].first.second;
2051 					else
2052 						ranges.emplace_back(volumes_and_ranges[j].first);
2053 				}
2054 				volume_ranges.emplace_back(std::move(ranges));
2055 				i = j;
2056 			} else
2057 				++ i;
2058 		}
2059 
2060 		if (! volume_ranges.empty())
2061 		{
2062 			bool equal_ranges = true;
2063 			for (size_t i = 1; i < volume_ranges.size(); ++ i) {
2064 				assert(! volume_ranges[i].empty());
2065 				if (volume_ranges.front() != volume_ranges[i]) {
2066 					equal_ranges = false;
2067 					break;
2068 				}
2069 			}
2070 
2071 			if (equal_ranges && volume_ranges.front().size() == 1 && volume_ranges.front().front() == t_layer_height_range(0, DBL_MAX)) {
2072 				// No modifier in this region was split to layer spans.
2073 				std::vector<const ModelVolume*> volumes;
2074 				for (const std::pair<t_layer_height_range, int> &volume_and_range : this->region_volumes[region_id]) {
2075 					const ModelVolume *volume = this->model_object()->volumes[volume_and_range.second];
2076 					if (volume->is_modifier())
2077 						volumes.emplace_back(volume);
2078 				}
2079 				out = this->slice_volumes(slice_zs, SlicingMode::Regular, volumes);
2080 			} else {
2081 				// Some modifier in this region was split to layer spans.
2082 				std::vector<char> merge;
2083 				for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) {
2084 					const std::vector<std::pair<t_layer_height_range, int>> &volumes_and_ranges = this->region_volumes[region_id];
2085 					for (size_t i = 0; i < volumes_and_ranges.size(); ) {
2086 						int 			   volume_id    = volumes_and_ranges[i].second;
2087 						const ModelVolume *model_volume = this->model_object()->volumes[volume_id];
2088 						if (model_volume->is_modifier()) {
2089 							BOOST_LOG_TRIVIAL(debug) << "Slicing modifiers - volume " << volume_id;
2090 							// Find the ranges of this volume. Ranges in volumes_and_ranges must not overlap for a single volume.
2091 							std::vector<t_layer_height_range> ranges;
2092 							ranges.emplace_back(volumes_and_ranges[i].first);
2093 							size_t j = i + 1;
2094 							for (; j < volumes_and_ranges.size() && volume_id == volumes_and_ranges[j].second; ++ j)
2095 								ranges.emplace_back(volumes_and_ranges[j].first);
2096 			                // slicing in parallel
2097 			                std::vector<ExPolygons> this_slices = this->slice_volume(slice_zs, ranges, SlicingMode::Regular, *model_volume);
2098                             // Variable this_slices could be empty if no value of slice_zs is within any of the ranges of this volume.
2099 			                if (out.empty()) {
2100 			                	out = std::move(this_slices);
2101 			                	merge.assign(out.size(), false);
2102 			                } else if (!this_slices.empty()) {
2103                                 assert(out.size() == this_slices.size());
2104 			                	for (size_t i = 0; i < out.size(); ++ i)
2105                                     if (! this_slices[i].empty()) {
2106 			                			if (! out[i].empty()) {
2107 			                				append(out[i], this_slices[i]);
2108 			                				merge[i] = true;
2109 			                			} else
2110 			                				out[i] = std::move(this_slices[i]);
2111                                     }
2112 			                }
2113 							i = j;
2114 						} else
2115 							++ i;
2116 					}
2117 				}
2118 				for (size_t i = 0; i < merge.size(); ++ i)
2119 					if (merge[i])
2120 						out[i] = union_ex(out[i]);
2121 			}
2122 		}
2123 	}
2124 
2125 	return out;
2126 }
2127 
slice_support_volumes(const ModelVolumeType & model_volume_type) const2128 std::vector<ExPolygons> PrintObject::slice_support_volumes(const ModelVolumeType &model_volume_type) const
2129 {
2130     std::vector<const ModelVolume*> volumes;
2131     for (const ModelVolume *volume : this->model_object()->volumes)
2132         if (volume->type() == model_volume_type)
2133             volumes.emplace_back(volume);
2134     std::vector<float> zs;
2135     zs.reserve(this->layers().size());
2136     for (const Layer *l : this->layers())
2137         zs.emplace_back((float)l->slice_z);
2138     return this->slice_volumes(zs, SlicingMode::Regular, volumes);
2139 }
2140 
2141 //FIXME The admesh repair function may break the face connectivity, rather refresh it here as the slicing code relies on it.
fix_mesh_connectivity(TriangleMesh & mesh)2142 static void fix_mesh_connectivity(TriangleMesh &mesh)
2143 {
2144     auto nr_degenerated = mesh.stl.stats.degenerate_facets;
2145     stl_check_facets_exact(&mesh.stl);
2146     if (nr_degenerated != mesh.stl.stats.degenerate_facets)
2147         // stl_check_facets_exact() removed some newly degenerated faces. Some faces could become degenerate after some mesh transformation.
2148         stl_generate_shared_vertices(&mesh.stl, mesh.its);
2149 }
2150 
slice_volumes(const std::vector<float> & z,SlicingMode mode,size_t slicing_mode_normal_below_layer,SlicingMode mode_below,const std::vector<const ModelVolume * > & volumes) const2151 std::vector<ExPolygons> PrintObject::slice_volumes(
2152     const std::vector<float> &z,
2153     SlicingMode mode, size_t slicing_mode_normal_below_layer, SlicingMode mode_below,
2154     const std::vector<const ModelVolume*> &volumes) const
2155 {
2156     std::vector<ExPolygons> layers;
2157     if (! volumes.empty()) {
2158         // Compose mesh.
2159         //FIXME better to perform slicing over each volume separately and then to use a Boolean operation to merge them.
2160 		TriangleMesh mesh(volumes.front()->mesh());
2161         mesh.transform(volumes.front()->get_matrix(), true);
2162 		assert(mesh.repaired);
2163 		if (volumes.size() == 1 && mesh.repaired)
2164             fix_mesh_connectivity(mesh);
2165         for (size_t idx_volume = 1; idx_volume < volumes.size(); ++ idx_volume) {
2166             const ModelVolume &model_volume = *volumes[idx_volume];
2167             TriangleMesh vol_mesh(model_volume.mesh());
2168             vol_mesh.transform(model_volume.get_matrix(), true);
2169             mesh.merge(vol_mesh);
2170         }
2171         if (mesh.stl.stats.number_of_facets > 0) {
2172             mesh.transform(m_trafo, true);
2173             // apply XY shift
2174             mesh.translate(- unscale<float>(m_center_offset.x()), - unscale<float>(m_center_offset.y()), 0);
2175             // perform actual slicing
2176             const Print *print = this->print();
2177             auto callback = TriangleMeshSlicer::throw_on_cancel_callback_type([print](){print->throw_if_canceled();});
2178             // TriangleMeshSlicer needs shared vertices, also this calls the repair() function.
2179             mesh.require_shared_vertices();
2180             TriangleMeshSlicer mslicer;
2181             mslicer.init(&mesh, callback);
2182 			mslicer.slice(z, mode, slicing_mode_normal_below_layer, mode_below, float(m_config.slice_closing_radius.value), &layers, callback);
2183             m_print->throw_if_canceled();
2184         }
2185     }
2186     return layers;
2187 }
2188 
slice_volume(const std::vector<float> & z,SlicingMode mode,const ModelVolume & volume) const2189 std::vector<ExPolygons> PrintObject::slice_volume(const std::vector<float> &z, SlicingMode mode, const ModelVolume &volume) const
2190 {
2191     std::vector<ExPolygons> layers;
2192     if (! z.empty()) {
2193 	    // Compose mesh.
2194 	    //FIXME better to split the mesh into separate shells, perform slicing over each shell separately and then to use a Boolean operation to merge them.
2195 	    TriangleMesh mesh(volume.mesh());
2196 	    mesh.transform(volume.get_matrix(), true);
2197 		if (mesh.repaired)
2198             fix_mesh_connectivity(mesh);
2199 	    if (mesh.stl.stats.number_of_facets > 0) {
2200 	        mesh.transform(m_trafo, true);
2201 	        // apply XY shift
2202 	        mesh.translate(- unscale<float>(m_center_offset.x()), - unscale<float>(m_center_offset.y()), 0);
2203 	        // perform actual slicing
2204 	        TriangleMeshSlicer mslicer;
2205 	        const Print *print = this->print();
2206 	        auto callback = TriangleMeshSlicer::throw_on_cancel_callback_type([print](){print->throw_if_canceled();});
2207 	        // TriangleMeshSlicer needs the shared vertices.
2208 	        mesh.require_shared_vertices();
2209 	        mslicer.init(&mesh, callback);
2210 	        mslicer.slice(z, mode, float(m_config.slice_closing_radius.value), &layers, callback);
2211 	        m_print->throw_if_canceled();
2212 	    }
2213 	}
2214     return layers;
2215 }
2216 
2217 // Filter the zs not inside the ranges. The ranges are closed at the bottom and open at the top, they are sorted lexicographically and non overlapping.
slice_volume(const std::vector<float> & z,const std::vector<t_layer_height_range> & ranges,SlicingMode mode,const ModelVolume & volume) const2218 std::vector<ExPolygons> PrintObject::slice_volume(const std::vector<float> &z, const std::vector<t_layer_height_range> &ranges, SlicingMode mode, const ModelVolume &volume) const
2219 {
2220 	std::vector<ExPolygons> out;
2221 	if (! z.empty() && ! ranges.empty()) {
2222 		if (ranges.size() == 1 && z.front() >= ranges.front().first && z.back() < ranges.front().second) {
2223 			// All layers fit into a single range.
2224 			out = this->slice_volume(z, mode, volume);
2225 		} else {
2226 			std::vector<float> 					   z_filtered;
2227 			std::vector<std::pair<size_t, size_t>> n_filtered;
2228 			z_filtered.reserve(z.size());
2229 			n_filtered.reserve(2 * ranges.size());
2230 			size_t i = 0;
2231 			for (const t_layer_height_range &range : ranges) {
2232 				for (; i < z.size() && z[i] < range.first; ++ i) ;
2233 				size_t first = i;
2234 				for (; i < z.size() && z[i] < range.second; ++ i)
2235 					z_filtered.emplace_back(z[i]);
2236 				if (i > first)
2237 					n_filtered.emplace_back(std::make_pair(first, i));
2238 			}
2239 			if (! n_filtered.empty()) {
2240 				std::vector<ExPolygons> layers = this->slice_volume(z_filtered, mode, volume);
2241 				out.assign(z.size(), ExPolygons());
2242 				i = 0;
2243 				for (const std::pair<size_t, size_t> &span : n_filtered)
2244 					for (size_t j = span.first; j < span.second; ++ j)
2245 						out[j] = std::move(layers[i ++]);
2246 			}
2247 		}
2248 	}
2249 	return out;
2250 }
2251 
_fix_slicing_errors()2252 std::string PrintObject::_fix_slicing_errors()
2253 {
2254     // Collect layers with slicing errors.
2255     // These layers will be fixed in parallel.
2256     std::vector<size_t> buggy_layers;
2257     buggy_layers.reserve(m_layers.size());
2258     for (size_t idx_layer = 0; idx_layer < m_layers.size(); ++ idx_layer)
2259         if (m_layers[idx_layer]->slicing_errors)
2260             buggy_layers.push_back(idx_layer);
2261 
2262     BOOST_LOG_TRIVIAL(debug) << "Slicing objects - fixing slicing errors in parallel - begin";
2263     tbb::parallel_for(
2264         tbb::blocked_range<size_t>(0, buggy_layers.size()),
2265         [this, &buggy_layers](const tbb::blocked_range<size_t>& range) {
2266             for (size_t buggy_layer_idx = range.begin(); buggy_layer_idx < range.end(); ++ buggy_layer_idx) {
2267                 m_print->throw_if_canceled();
2268                 size_t idx_layer = buggy_layers[buggy_layer_idx];
2269                 Layer *layer     = m_layers[idx_layer];
2270                 assert(layer->slicing_errors);
2271                 // Try to repair the layer surfaces by merging all contours and all holes from neighbor layers.
2272                 // BOOST_LOG_TRIVIAL(trace) << "Attempting to repair layer" << idx_layer;
2273                 for (size_t region_id = 0; region_id < layer->m_regions.size(); ++ region_id) {
2274                     LayerRegion *layerm = layer->m_regions[region_id];
2275                     // Find the first valid layer below / above the current layer.
2276                     const Surfaces *upper_surfaces = nullptr;
2277                     const Surfaces *lower_surfaces = nullptr;
2278                     for (size_t j = idx_layer + 1; j < m_layers.size(); ++ j)
2279                         if (! m_layers[j]->slicing_errors) {
2280                             upper_surfaces = &m_layers[j]->regions()[region_id]->slices.surfaces;
2281                             break;
2282                         }
2283                     for (int j = int(idx_layer) - 1; j >= 0; -- j)
2284                         if (! m_layers[j]->slicing_errors) {
2285                             lower_surfaces = &m_layers[j]->regions()[region_id]->slices.surfaces;
2286                             break;
2287                         }
2288                     // Collect outer contours and holes from the valid layers above & below.
2289                     Polygons outer;
2290                     outer.reserve(
2291                         ((upper_surfaces == nullptr) ? 0 : upper_surfaces->size()) +
2292                         ((lower_surfaces == nullptr) ? 0 : lower_surfaces->size()));
2293                     size_t num_holes = 0;
2294                     if (upper_surfaces)
2295                         for (const auto &surface : *upper_surfaces) {
2296                             outer.push_back(surface.expolygon.contour);
2297                             num_holes += surface.expolygon.holes.size();
2298                         }
2299                     if (lower_surfaces)
2300                         for (const auto &surface : *lower_surfaces) {
2301                             outer.push_back(surface.expolygon.contour);
2302                             num_holes += surface.expolygon.holes.size();
2303                         }
2304                     Polygons holes;
2305                     holes.reserve(num_holes);
2306                     if (upper_surfaces)
2307                         for (const auto &surface : *upper_surfaces)
2308                             polygons_append(holes, surface.expolygon.holes);
2309                     if (lower_surfaces)
2310                         for (const auto &surface : *lower_surfaces)
2311                             polygons_append(holes, surface.expolygon.holes);
2312                     layerm->slices.set(diff_ex(union_(outer), holes, false), stInternal);
2313                 }
2314                 // Update layer slices after repairing the single regions.
2315                 layer->make_slices();
2316             }
2317         });
2318     m_print->throw_if_canceled();
2319     BOOST_LOG_TRIVIAL(debug) << "Slicing objects - fixing slicing errors in parallel - end";
2320 
2321     // remove empty layers from bottom
2322     while (! m_layers.empty() && (m_layers.front()->lslices.empty() || m_layers.front()->empty())) {
2323         delete m_layers.front();
2324         m_layers.erase(m_layers.begin());
2325         m_layers.front()->lower_layer = nullptr;
2326         for (size_t i = 0; i < m_layers.size(); ++ i)
2327             m_layers[i]->set_id(m_layers[i]->id() - 1);
2328     }
2329 
2330     return buggy_layers.empty() ? "" :
2331         "The model has overlapping or self-intersecting facets. I tried to repair it, "
2332         "however you might want to check the results or repair the input file and retry.\n";
2333 }
2334 
2335 // Simplify the sliced model, if "resolution" configuration parameter > 0.
2336 // The simplification is problematic, because it simplifies the slices independent from each other,
2337 // which makes the simplified discretization visible on the object surface.
simplify_slices(double distance)2338 void PrintObject::simplify_slices(double distance)
2339 {
2340     BOOST_LOG_TRIVIAL(debug) << "Slicing objects - siplifying slices in parallel - begin";
2341     tbb::parallel_for(
2342         tbb::blocked_range<size_t>(0, m_layers.size()),
2343         [this, distance](const tbb::blocked_range<size_t>& range) {
2344             for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
2345                 m_print->throw_if_canceled();
2346                 Layer *layer = m_layers[layer_idx];
2347                 for (size_t region_idx = 0; region_idx < layer->m_regions.size(); ++ region_idx)
2348                     layer->m_regions[region_idx]->slices.simplify(distance);
2349 				{
2350 					ExPolygons simplified;
2351 					for (const ExPolygon &expoly : layer->lslices)
2352 						expoly.simplify(distance, &simplified);
2353 					layer->lslices = std::move(simplified);
2354 				}
2355             }
2356         });
2357     BOOST_LOG_TRIVIAL(debug) << "Slicing objects - siplifying slices in parallel - end";
2358 }
2359 
2360 // Only active if config->infill_only_where_needed. This step trims the sparse infill,
2361 // so it acts as an internal support. It maintains all other infill types intact.
2362 // Here the internal surfaces and perimeters have to be supported by the sparse infill.
2363 //FIXME The surfaces are supported by a sparse infill, but the sparse infill is only as large as the area to support.
2364 // Likely the sparse infill will not be anchored correctly, so it will not work as intended.
2365 // Also one wishes the perimeters to be supported by a full infill.
2366 // Idempotence of this method is guaranteed by the fact that we don't remove things from
2367 // fill_surfaces but we only turn them into VOID surfaces, thus preserving the boundaries.
clip_fill_surfaces()2368 void PrintObject::clip_fill_surfaces()
2369 {
2370     if (! m_config.infill_only_where_needed.value ||
2371         ! std::any_of(this->print()->regions().begin(), this->print()->regions().end(),
2372             [](const PrintRegion *region) { return region->config().fill_density > 0; }))
2373         return;
2374 
2375     // We only want infill under ceilings; this is almost like an
2376     // internal support material.
2377     // Proceed top-down, skipping the bottom layer.
2378     Polygons upper_internal;
2379     for (int layer_id = int(m_layers.size()) - 1; layer_id > 0; -- layer_id) {
2380         Layer *layer       = m_layers[layer_id];
2381         Layer *lower_layer = m_layers[layer_id - 1];
2382         // Detect things that we need to support.
2383         // Cummulative slices.
2384         Polygons slices;
2385         polygons_append(slices, layer->lslices);
2386         // Cummulative fill surfaces.
2387         Polygons fill_surfaces;
2388         // Solid surfaces to be supported.
2389         Polygons overhangs;
2390         for (const LayerRegion *layerm : layer->m_regions)
2391             for (const Surface &surface : layerm->fill_surfaces.surfaces) {
2392                 Polygons polygons = to_polygons(surface.expolygon);
2393                 if (surface.is_solid())
2394                     polygons_append(overhangs, polygons);
2395                 polygons_append(fill_surfaces, std::move(polygons));
2396             }
2397         Polygons lower_layer_fill_surfaces;
2398         Polygons lower_layer_internal_surfaces;
2399         for (const LayerRegion *layerm : lower_layer->m_regions)
2400             for (const Surface &surface : layerm->fill_surfaces.surfaces) {
2401                 Polygons polygons = to_polygons(surface.expolygon);
2402                 if (surface.surface_type == stInternal || surface.surface_type == stInternalVoid)
2403                     polygons_append(lower_layer_internal_surfaces, polygons);
2404                 polygons_append(lower_layer_fill_surfaces, std::move(polygons));
2405             }
2406         // We also need to support perimeters when there's at least one full unsupported loop
2407         {
2408             // Get perimeters area as the difference between slices and fill_surfaces
2409             // Only consider the area that is not supported by lower perimeters
2410             Polygons perimeters = intersection(diff(slices, fill_surfaces), lower_layer_fill_surfaces);
2411             // Only consider perimeter areas that are at least one extrusion width thick.
2412             //FIXME Offset2 eats out from both sides, while the perimeters are create outside in.
2413             //Should the pw not be half of the current value?
2414             float pw = FLT_MAX;
2415             for (const LayerRegion *layerm : layer->m_regions)
2416                 pw = std::min(pw, (float)layerm->flow(frPerimeter).scaled_width());
2417             // Append such thick perimeters to the areas that need support
2418             polygons_append(overhangs, offset2(perimeters, -pw, +pw));
2419         }
2420         // Find new internal infill.
2421         polygons_append(overhangs, std::move(upper_internal));
2422         upper_internal = intersection(overhangs, lower_layer_internal_surfaces);
2423         // Apply new internal infill to regions.
2424         for (LayerRegion *layerm : lower_layer->m_regions) {
2425             if (layerm->region()->config().fill_density.value == 0)
2426                 continue;
2427             SurfaceType internal_surface_types[] = { stInternal, stInternalVoid };
2428             Polygons internal;
2429             for (Surface &surface : layerm->fill_surfaces.surfaces)
2430                 if (surface.surface_type == stInternal || surface.surface_type == stInternalVoid)
2431                     polygons_append(internal, std::move(surface.expolygon));
2432             layerm->fill_surfaces.remove_types(internal_surface_types, 2);
2433             layerm->fill_surfaces.append(intersection_ex(internal, upper_internal, true), stInternal);
2434             layerm->fill_surfaces.append(diff_ex        (internal, upper_internal, true), stInternalVoid);
2435             // If there are voids it means that our internal infill is not adjacent to
2436             // perimeters. In this case it would be nice to add a loop around infill to
2437             // make it more robust and nicer. TODO.
2438 #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
2439             layerm->export_region_fill_surfaces_to_svg_debug("6_clip_fill_surfaces");
2440 #endif
2441         }
2442         m_print->throw_if_canceled();
2443     }
2444 }
2445 
discover_horizontal_shells()2446 void PrintObject::discover_horizontal_shells()
2447 {
2448     BOOST_LOG_TRIVIAL(trace) << "discover_horizontal_shells()";
2449 
2450     for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) {
2451         for (size_t i = 0; i < m_layers.size(); ++ i) {
2452             m_print->throw_if_canceled();
2453             Layer 					*layer  = m_layers[i];
2454             LayerRegion             *layerm = layer->regions()[region_id];
2455             const PrintRegionConfig &region_config = layerm->region()->config();
2456             if (region_config.solid_infill_every_layers.value > 0 && region_config.fill_density.value > 0 &&
2457                 (i % region_config.solid_infill_every_layers) == 0) {
2458                 // Insert a solid internal layer. Mark stInternal surfaces as stInternalSolid or stInternalBridge.
2459                 SurfaceType type = (region_config.fill_density == 100) ? stInternalSolid : stInternalBridge;
2460                 for (Surface &surface : layerm->fill_surfaces.surfaces)
2461                     if (surface.surface_type == stInternal)
2462                         surface.surface_type = type;
2463             }
2464 
2465             // If ensure_vertical_shell_thickness, then the rest has already been performed by discover_vertical_shells().
2466             if (region_config.ensure_vertical_shell_thickness.value)
2467                 continue;
2468 
2469             coordf_t print_z  = layer->print_z;
2470             coordf_t bottom_z = layer->bottom_z();
2471             for (size_t idx_surface_type = 0; idx_surface_type < 3; ++ idx_surface_type) {
2472                 m_print->throw_if_canceled();
2473                 SurfaceType type = (idx_surface_type == 0) ? stTop : (idx_surface_type == 1) ? stBottom : stBottomBridge;
2474                 int num_solid_layers = (type == stTop) ? region_config.top_solid_layers.value : region_config.bottom_solid_layers.value;
2475                 if (num_solid_layers == 0)
2476                 	continue;
2477                 // Find slices of current type for current layer.
2478                 // Use slices instead of fill_surfaces, because they also include the perimeter area,
2479                 // which needs to be propagated in shells; we need to grow slices like we did for
2480                 // fill_surfaces though. Using both ungrown slices and grown fill_surfaces will
2481                 // not work in some situations, as there won't be any grown region in the perimeter
2482                 // area (this was seen in a model where the top layer had one extra perimeter, thus
2483                 // its fill_surfaces were thinner than the lower layer's infill), however it's the best
2484                 // solution so far. Growing the external slices by EXTERNAL_INFILL_MARGIN will put
2485                 // too much solid infill inside nearly-vertical slopes.
2486 
2487                 // Surfaces including the area of perimeters. Everything, that is visible from the top / bottom
2488                 // (not covered by a layer above / below).
2489                 // This does not contain the areas covered by perimeters!
2490                 Polygons solid;
2491                 for (const Surface &surface : layerm->slices.surfaces)
2492                     if (surface.surface_type == type)
2493                         polygons_append(solid, to_polygons(surface.expolygon));
2494                 // Infill areas (slices without the perimeters).
2495                 for (const Surface &surface : layerm->fill_surfaces.surfaces)
2496                     if (surface.surface_type == type)
2497                         polygons_append(solid, to_polygons(surface.expolygon));
2498                 if (solid.empty())
2499                     continue;
2500 //                Slic3r::debugf "Layer %d has %s surfaces\n", $i, ($type == stTop) ? 'top' : 'bottom';
2501 
2502                 // Scatter top / bottom regions to other layers. Scattering process is inherently serial, it is difficult to parallelize without locking.
2503                 for (int n = (type == stTop) ? int(i) - 1 : int(i) + 1;
2504                 	(type == stTop) ?
2505                 		(n >= 0                   && (int(i) - n < num_solid_layers ||
2506                 								 	  print_z - m_layers[n]->print_z < region_config.top_solid_min_thickness.value - EPSILON)) :
2507                 		(n < int(m_layers.size()) && (n - int(i) < num_solid_layers ||
2508                 									  m_layers[n]->bottom_z() - bottom_z < region_config.bottom_solid_min_thickness.value - EPSILON));
2509                 	(type == stTop) ? -- n : ++ n)
2510                 {
2511 //                    Slic3r::debugf "  looking for neighbors on layer %d...\n", $n;
2512                     // Reference to the lower layer of a TOP surface, or an upper layer of a BOTTOM surface.
2513                     LayerRegion *neighbor_layerm = m_layers[n]->regions()[region_id];
2514 
2515                     // find intersection between neighbor and current layer's surfaces
2516                     // intersections have contours and holes
2517                     // we update $solid so that we limit the next neighbor layer to the areas that were
2518                     // found on this one - in other words, solid shells on one layer (for a given external surface)
2519                     // are always a subset of the shells found on the previous shell layer
2520                     // this approach allows for DWIM in hollow sloping vases, where we want bottom
2521                     // shells to be generated in the base but not in the walls (where there are many
2522                     // narrow bottom surfaces): reassigning $solid will consider the 'shadow' of the
2523                     // upper perimeter as an obstacle and shell will not be propagated to more upper layers
2524                     //FIXME How does it work for stInternalBRIDGE? This is set for sparse infill. Likely this does not work.
2525                     Polygons new_internal_solid;
2526                     {
2527                         Polygons internal;
2528                         for (const Surface &surface : neighbor_layerm->fill_surfaces.surfaces)
2529                             if (surface.surface_type == stInternal || surface.surface_type == stInternalSolid)
2530                                 polygons_append(internal, to_polygons(surface.expolygon));
2531                         new_internal_solid = intersection(solid, internal, true);
2532                     }
2533                     if (new_internal_solid.empty()) {
2534                         // No internal solid needed on this layer. In order to decide whether to continue
2535                         // searching on the next neighbor (thus enforcing the configured number of solid
2536                         // layers, use different strategies according to configured infill density:
2537                         if (region_config.fill_density.value == 0) {
2538                             // If user expects the object to be void (for example a hollow sloping vase),
2539                             // don't continue the search. In this case, we only generate the external solid
2540                             // shell if the object would otherwise show a hole (gap between perimeters of
2541                             // the two layers), and internal solid shells are a subset of the shells found
2542                             // on each previous layer.
2543                             goto EXTERNAL;
2544                         } else {
2545                             // If we have internal infill, we can generate internal solid shells freely.
2546                             continue;
2547                         }
2548                     }
2549 
2550                     if (region_config.fill_density.value == 0) {
2551                         // if we're printing a hollow object we discard any solid shell thinner
2552                         // than a perimeter width, since it's probably just crossing a sloping wall
2553                         // and it's not wanted in a hollow print even if it would make sense when
2554                         // obeying the solid shell count option strictly (DWIM!)
2555                         float margin = float(neighbor_layerm->flow(frExternalPerimeter).scaled_width());
2556                         Polygons too_narrow = diff(
2557                             new_internal_solid,
2558                             offset2(new_internal_solid, -margin, +margin, jtMiter, 5),
2559                             true);
2560                         // Trim the regularized region by the original region.
2561                         if (! too_narrow.empty())
2562                             new_internal_solid = solid = diff(new_internal_solid, too_narrow);
2563                     }
2564 
2565                     // make sure the new internal solid is wide enough, as it might get collapsed
2566                     // when spacing is added in Fill.pm
2567                     {
2568                         //FIXME Vojtech: Disable this and you will be sorry.
2569                         // https://github.com/prusa3d/PrusaSlicer/issues/26 bottom
2570                         float margin = 3.f * layerm->flow(frSolidInfill).scaled_width(); // require at least this size
2571                         // we use a higher miterLimit here to handle areas with acute angles
2572                         // in those cases, the default miterLimit would cut the corner and we'd
2573                         // get a triangle in $too_narrow; if we grow it below then the shell
2574                         // would have a different shape from the external surface and we'd still
2575                         // have the same angle, so the next shell would be grown even more and so on.
2576                         Polygons too_narrow = diff(
2577                             new_internal_solid,
2578                             offset2(new_internal_solid, -margin, +margin, ClipperLib::jtMiter, 5),
2579                             true);
2580                         if (! too_narrow.empty()) {
2581                             // grow the collapsing parts and add the extra area to  the neighbor layer
2582                             // as well as to our original surfaces so that we support this
2583                             // additional area in the next shell too
2584                             // make sure our grown surfaces don't exceed the fill area
2585                             Polygons internal;
2586                             for (const Surface &surface : neighbor_layerm->fill_surfaces.surfaces)
2587                                 if (surface.is_internal() && !surface.is_bridge())
2588                                     polygons_append(internal, to_polygons(surface.expolygon));
2589                             polygons_append(new_internal_solid,
2590                                 intersection(
2591                                     offset(too_narrow, +margin),
2592                                     // Discard bridges as they are grown for anchoring and we can't
2593                                     // remove such anchors. (This may happen when a bridge is being
2594                                     // anchored onto a wall where little space remains after the bridge
2595                                     // is grown, and that little space is an internal solid shell so
2596                                     // it triggers this too_narrow logic.)
2597                                     internal));
2598                             // see https://github.com/prusa3d/PrusaSlicer/pull/3426
2599                             // solid = new_internal_solid;
2600                         }
2601                     }
2602 
2603                     // internal-solid are the union of the existing internal-solid surfaces
2604                     // and new ones
2605                     SurfaceCollection backup = std::move(neighbor_layerm->fill_surfaces);
2606                     polygons_append(new_internal_solid, to_polygons(backup.filter_by_type(stInternalSolid)));
2607                     ExPolygons internal_solid = union_ex(new_internal_solid, false);
2608                     // assign new internal-solid surfaces to layer
2609                     neighbor_layerm->fill_surfaces.set(internal_solid, stInternalSolid);
2610                     // subtract intersections from layer surfaces to get resulting internal surfaces
2611                     Polygons polygons_internal = to_polygons(std::move(internal_solid));
2612                     ExPolygons internal = diff_ex(
2613                         to_polygons(backup.filter_by_type(stInternal)),
2614                         polygons_internal,
2615                         true);
2616                     // assign resulting internal surfaces to layer
2617                     neighbor_layerm->fill_surfaces.append(internal, stInternal);
2618                     polygons_append(polygons_internal, to_polygons(std::move(internal)));
2619                     // assign top and bottom surfaces to layer
2620                     SurfaceType surface_types_solid[] = { stTop, stBottom, stBottomBridge };
2621                     backup.keep_types(surface_types_solid, 3);
2622                     std::vector<SurfacesPtr> top_bottom_groups;
2623                     backup.group(&top_bottom_groups);
2624                     for (SurfacesPtr &group : top_bottom_groups)
2625                         neighbor_layerm->fill_surfaces.append(
2626                             diff_ex(to_polygons(group), polygons_internal),
2627                             // Use an existing surface as a template, it carries the bridge angle etc.
2628                             *group.front());
2629                 }
2630 		EXTERNAL:;
2631             } // foreach type (stTop, stBottom, stBottomBridge)
2632         } // for each layer
2633     } // for each region
2634 
2635 #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
2636     for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) {
2637         for (const Layer *layer : m_layers) {
2638             const LayerRegion *layerm = layer->m_regions[region_id];
2639             layerm->export_region_slices_to_svg_debug("5_discover_horizontal_shells");
2640             layerm->export_region_fill_surfaces_to_svg_debug("5_discover_horizontal_shells");
2641         } // for each layer
2642     } // for each region
2643 #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
2644 }
2645 
2646 // combine fill surfaces across layers to honor the "infill every N layers" option
2647 // Idempotence of this method is guaranteed by the fact that we don't remove things from
2648 // fill_surfaces but we only turn them into VOID surfaces, thus preserving the boundaries.
combine_infill()2649 void PrintObject::combine_infill()
2650 {
2651     // Work on each region separately.
2652     for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) {
2653         const PrintRegion *region = this->print()->regions()[region_id];
2654         const size_t every = region->config().infill_every_layers.value;
2655         if (every < 2 || region->config().fill_density == 0.)
2656             continue;
2657         // Limit the number of combined layers to the maximum height allowed by this regions' nozzle.
2658         //FIXME limit the layer height to max_layer_height
2659         double nozzle_diameter = std::min(
2660             this->print()->config().nozzle_diameter.get_at(region->config().infill_extruder.value - 1),
2661             this->print()->config().nozzle_diameter.get_at(region->config().solid_infill_extruder.value - 1));
2662         // define the combinations
2663         std::vector<size_t> combine(m_layers.size(), 0);
2664         {
2665             double current_height = 0.;
2666             size_t num_layers = 0;
2667             for (size_t layer_idx = 0; layer_idx < m_layers.size(); ++ layer_idx) {
2668                 m_print->throw_if_canceled();
2669                 const Layer *layer = m_layers[layer_idx];
2670                 if (layer->id() == 0)
2671                     // Skip first print layer (which may not be first layer in array because of raft).
2672                     continue;
2673                 // Check whether the combination of this layer with the lower layers' buffer
2674                 // would exceed max layer height or max combined layer count.
2675                 if (current_height + layer->height >= nozzle_diameter + EPSILON || num_layers >= every) {
2676                     // Append combination to lower layer.
2677                     combine[layer_idx - 1] = num_layers;
2678                     current_height = 0.;
2679                     num_layers = 0;
2680                 }
2681                 current_height += layer->height;
2682                 ++ num_layers;
2683             }
2684 
2685             // Append lower layers (if any) to uppermost layer.
2686             combine[m_layers.size() - 1] = num_layers;
2687         }
2688 
2689         // loop through layers to which we have assigned layers to combine
2690         for (size_t layer_idx = 0; layer_idx < m_layers.size(); ++ layer_idx) {
2691             m_print->throw_if_canceled();
2692             size_t num_layers = combine[layer_idx];
2693 			if (num_layers <= 1)
2694                 continue;
2695             // Get all the LayerRegion objects to be combined.
2696             std::vector<LayerRegion*> layerms;
2697             layerms.reserve(num_layers);
2698 			for (size_t i = layer_idx + 1 - num_layers; i <= layer_idx; ++ i)
2699                 layerms.emplace_back(m_layers[i]->regions()[region_id]);
2700             // We need to perform a multi-layer intersection, so let's split it in pairs.
2701             // Initialize the intersection with the candidates of the lowest layer.
2702             ExPolygons intersection = to_expolygons(layerms.front()->fill_surfaces.filter_by_type(stInternal));
2703             // Start looping from the second layer and intersect the current intersection with it.
2704             for (size_t i = 1; i < layerms.size(); ++ i)
2705                 intersection = intersection_ex(
2706                     to_polygons(intersection),
2707                     to_polygons(layerms[i]->fill_surfaces.filter_by_type(stInternal)),
2708                     false);
2709             double area_threshold = layerms.front()->infill_area_threshold();
2710             if (! intersection.empty() && area_threshold > 0.)
2711                 intersection.erase(std::remove_if(intersection.begin(), intersection.end(),
2712                     [area_threshold](const ExPolygon &expoly) { return expoly.area() <= area_threshold; }),
2713                     intersection.end());
2714             if (intersection.empty())
2715                 continue;
2716 //            Slic3r::debugf "  combining %d %s regions from layers %d-%d\n",
2717 //                scalar(@$intersection),
2718 //                ($type == stInternal ? 'internal' : 'internal-solid'),
2719 //                $layer_idx-($every-1), $layer_idx;
2720             // intersection now contains the regions that can be combined across the full amount of layers,
2721             // so let's remove those areas from all layers.
2722             Polygons intersection_with_clearance;
2723             intersection_with_clearance.reserve(intersection.size());
2724             float clearance_offset =
2725                 0.5f * layerms.back()->flow(frPerimeter).scaled_width() +
2726              // Because fill areas for rectilinear and honeycomb are grown
2727              // later to overlap perimeters, we need to counteract that too.
2728                 ((region->config().fill_pattern == ipRectilinear   ||
2729                   region->config().fill_pattern == ipMonotonic     ||
2730                   region->config().fill_pattern == ipGrid          ||
2731                   region->config().fill_pattern == ipLine          ||
2732                   region->config().fill_pattern == ipHoneycomb) ? 1.5f : 0.5f) *
2733                     layerms.back()->flow(frSolidInfill).scaled_width();
2734             for (ExPolygon &expoly : intersection)
2735                 polygons_append(intersection_with_clearance, offset(expoly, clearance_offset));
2736             for (LayerRegion *layerm : layerms) {
2737                 Polygons internal = to_polygons(layerm->fill_surfaces.filter_by_type(stInternal));
2738                 layerm->fill_surfaces.remove_type(stInternal);
2739                 layerm->fill_surfaces.append(diff_ex(internal, intersection_with_clearance, false), stInternal);
2740                 if (layerm == layerms.back()) {
2741                     // Apply surfaces back with adjusted depth to the uppermost layer.
2742                     Surface templ(stInternal, ExPolygon());
2743                     templ.thickness = 0.;
2744                     for (LayerRegion *layerm2 : layerms)
2745                         templ.thickness += layerm2->layer()->height;
2746                     templ.thickness_layers = (unsigned short)layerms.size();
2747                     layerm->fill_surfaces.append(intersection, templ);
2748                 } else {
2749                     // Save void surfaces.
2750                     layerm->fill_surfaces.append(
2751                         intersection_ex(internal, intersection_with_clearance, false),
2752                         stInternalVoid);
2753                 }
2754             }
2755         }
2756     }
2757 }
2758 
_generate_support_material()2759 void PrintObject::_generate_support_material()
2760 {
2761     PrintObjectSupportMaterial support_material(this, m_slicing_params);
2762     support_material.generate(*this);
2763 }
2764 
2765 
project_and_append_custom_facets(bool seam,EnforcerBlockerType type,std::vector<ExPolygons> & expolys) const2766 void PrintObject::project_and_append_custom_facets(
2767         bool seam, EnforcerBlockerType type, std::vector<ExPolygons>& expolys) const
2768 {
2769     for (const ModelVolume* mv : this->model_object()->volumes) {
2770         const indexed_triangle_set custom_facets = seam
2771                 ? mv->seam_facets.get_facets(*mv, type)
2772                 : mv->supported_facets.get_facets(*mv, type);
2773         if (! mv->is_model_part() || custom_facets.indices.empty())
2774             continue;
2775 
2776         const Transform3f& tr1 = mv->get_matrix().cast<float>();
2777         const Transform3f& tr2 = this->trafo().cast<float>();
2778         const Transform3f  tr  = tr2 * tr1;
2779         const float tr_det_sign = (tr.matrix().determinant() > 0. ? 1.f : -1.f);
2780 
2781 
2782         // The projection will be at most a pentagon. Let's minimize heap
2783         // reallocations by saving in in the following struct.
2784         // Points are used so that scaling can be done in parallel
2785         // and they can be moved from to create an ExPolygon later.
2786         struct LightPolygon {
2787             LightPolygon() { pts.reserve(5); }
2788             Points pts;
2789 
2790             void add(const Vec2f& pt) {
2791                 pts.emplace_back(scale_(pt.x()), scale_(pt.y()));
2792                 assert(pts.size() <= 5);
2793             }
2794         };
2795 
2796         // Structure to collect projected polygons. One element for each triangle.
2797         // Saves vector of polygons and layer_id of the first one.
2798         struct TriangleProjections {
2799             size_t first_layer_id;
2800             std::vector<LightPolygon> polygons;
2801         };
2802 
2803         // Vector to collect resulting projections from each triangle.
2804         std::vector<TriangleProjections> projections_of_triangles(custom_facets.indices.size());
2805 
2806         // Iterate over all triangles.
2807         tbb::parallel_for(
2808             tbb::blocked_range<size_t>(0, custom_facets.indices.size()),
2809             [&](const tbb::blocked_range<size_t>& range) {
2810             for (size_t idx = range.begin(); idx < range.end(); ++ idx) {
2811 
2812             std::array<Vec3f, 3> facet;
2813 
2814             // Transform the triangle into worlds coords.
2815             for (int i=0; i<3; ++i)
2816                 facet[i] = tr * custom_facets.vertices[custom_facets.indices[idx](i)];
2817 
2818             // Ignore triangles with upward-pointing normal. Don't forget about mirroring.
2819             float z_comp = (facet[1]-facet[0]).cross(facet[2]-facet[0]).z();
2820             if (! seam && tr_det_sign * z_comp > 0.)
2821                 continue;
2822 
2823             // Sort the three vertices according to z-coordinate.
2824             std::sort(facet.begin(), facet.end(),
2825                       [](const Vec3f& pt1, const Vec3f&pt2) {
2826                           return pt1.z() < pt2.z();
2827                       });
2828 
2829             std::array<Vec2f, 3> trianglef;
2830             for (int i=0; i<3; ++i) {
2831                 trianglef[i] = Vec2f(facet[i].x(), facet[i].y());
2832                 trianglef[i] -= Vec2f(unscale<float>(this->center_offset().x()),
2833                                       unscale<float>(this->center_offset().y()));
2834             }
2835 
2836             // Find lowest slice not below the triangle.
2837             auto it = std::lower_bound(layers().begin(), layers().end(), facet[0].z()+EPSILON,
2838                           [](const Layer* l1, float z) {
2839                                return l1->slice_z < z;
2840                           });
2841 
2842             // Count how many projections will be generated for this triangle
2843             // and allocate respective amount in projections_of_triangles.
2844             projections_of_triangles[idx].first_layer_id = it-layers().begin();
2845             size_t last_layer_id = projections_of_triangles[idx].first_layer_id;
2846             // The cast in the condition below is important. The comparison must
2847             // be an exact opposite of the one lower in the code where
2848             // the polygons are appended. And that one is on floats.
2849             while (last_layer_id + 1 < layers().size()
2850                 && float(layers()[last_layer_id]->slice_z) <= facet[2].z())
2851                 ++last_layer_id;
2852             projections_of_triangles[idx].polygons.resize(
2853                 last_layer_id - projections_of_triangles[idx].first_layer_id + 1);
2854 
2855             // Calculate how to move points on triangle sides per unit z increment.
2856             Vec2f ta(trianglef[1] - trianglef[0]);
2857             Vec2f tb(trianglef[2] - trianglef[0]);
2858             ta *= 1.f/(facet[1].z() - facet[0].z());
2859             tb *= 1.f/(facet[2].z() - facet[0].z());
2860 
2861             // Projection on current slice will be build directly in place.
2862             LightPolygon* proj = &projections_of_triangles[idx].polygons[0];
2863             proj->add(trianglef[0]);
2864 
2865             bool passed_first = false;
2866             bool stop = false;
2867 
2868             // Project a sub-polygon on all slices intersecting the triangle.
2869             while (it != layers().end()) {
2870                 const float z = float((*it)->slice_z);
2871 
2872                 // Projections of triangle sides intersections with slices.
2873                 // a moves along one side, b tracks the other.
2874                 Vec2f a;
2875                 Vec2f b;
2876 
2877                 // If the middle vertex was already passed, append the vertex
2878                 // and use ta for tracking the remaining side.
2879                 if (z > facet[1].z() && ! passed_first) {
2880                     proj->add(trianglef[1]);
2881                     ta = trianglef[2]-trianglef[1];
2882                     ta *= 1.f/(facet[2].z() - facet[1].z());
2883                     passed_first = true;
2884                 }
2885 
2886                 // This slice is above the triangle already.
2887                 if (z > facet[2].z() || it+1 == layers().end()) {
2888                     proj->add(trianglef[2]);
2889                     stop = true;
2890                 }
2891                 else {
2892                     // Move a, b along the side it currently tracks to get
2893                     // projected intersection with current slice.
2894                     a = passed_first ? (trianglef[1]+ta*(z-facet[1].z()))
2895                                      : (trianglef[0]+ta*(z-facet[0].z()));
2896                     b = trianglef[0]+tb*(z-facet[0].z());
2897                     proj->add(a);
2898                     proj->add(b);
2899                 }
2900 
2901                if (stop)
2902                     break;
2903 
2904                 // Advance to the next layer.
2905                 ++it;
2906                 ++proj;
2907                 assert(proj <= &projections_of_triangles[idx].polygons.back() );
2908 
2909                 // a, b are first two points of the polygon for the next layer.
2910                 proj->add(b);
2911                 proj->add(a);
2912             }
2913         }
2914         }); // end of parallel_for
2915 
2916         // Make sure that the output vector can be used.
2917         expolys.resize(layers().size());
2918 
2919         // Now append the collected polygons to respective layers.
2920         for (auto& trg : projections_of_triangles) {
2921             int layer_id = int(trg.first_layer_id);
2922             for (const LightPolygon& poly : trg.polygons) {
2923                 if (layer_id >= int(expolys.size()))
2924                     break; // part of triangle could be projected above top layer
2925                 expolys[layer_id].emplace_back(std::move(poly.pts));
2926                 ++layer_id;
2927             }
2928         }
2929 
2930     } // loop over ModelVolumes
2931 }
2932 
2933 
2934 
get_layer_at_printz(coordf_t print_z) const2935 const Layer* PrintObject::get_layer_at_printz(coordf_t print_z) const {
2936     auto it = Slic3r::lower_bound_by_predicate(m_layers.begin(), m_layers.end(), [print_z](const Layer *layer) { return layer->print_z < print_z; });
2937     return (it == m_layers.end() || (*it)->print_z != print_z) ? nullptr : *it;
2938 }
2939 
2940 
2941 
get_layer_at_printz(coordf_t print_z)2942 Layer* PrintObject::get_layer_at_printz(coordf_t print_z) { return const_cast<Layer*>(std::as_const(*this).get_layer_at_printz(print_z)); }
2943 
2944 
2945 
2946 // Get a layer approximately at print_z.
get_layer_at_printz(coordf_t print_z,coordf_t epsilon) const2947 const Layer* PrintObject::get_layer_at_printz(coordf_t print_z, coordf_t epsilon) const {
2948     coordf_t limit = print_z - epsilon;
2949     auto it = Slic3r::lower_bound_by_predicate(m_layers.begin(), m_layers.end(), [limit](const Layer *layer) { return layer->print_z < limit; });
2950     return (it == m_layers.end() || (*it)->print_z > print_z + epsilon) ? nullptr : *it;
2951 }
2952 
2953 
2954 
get_layer_at_printz(coordf_t print_z,coordf_t epsilon)2955 Layer* PrintObject::get_layer_at_printz(coordf_t print_z, coordf_t epsilon) { return const_cast<Layer*>(std::as_const(*this).get_layer_at_printz(print_z, epsilon)); }
2956 
get_first_layer_bellow_printz(coordf_t print_z,coordf_t epsilon) const2957 const Layer *PrintObject::get_first_layer_bellow_printz(coordf_t print_z, coordf_t epsilon) const
2958 {
2959     coordf_t limit = print_z + epsilon;
2960     auto it = Slic3r::lower_bound_by_predicate(m_layers.begin(), m_layers.end(), [limit](const Layer *layer) { return layer->print_z < limit; });
2961     return (it == m_layers.begin()) ? nullptr : *(--it);
2962 }
2963 
2964 } // namespace Slic3r
2965