diff --git a/src/libslic3r/ClipperUtils.cpp b/src/libslic3r/ClipperUtils.cpp index a49665ae5..7216c7509 100644 --- a/src/libslic3r/ClipperUtils.cpp +++ b/src/libslic3r/ClipperUtils.cpp @@ -461,6 +461,8 @@ static inline Polygons _clipper(ClipperLib::ClipType clipType, TSubj &&subject, Slic3r::Polygons diff(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset) { return _clipper(ClipperLib::ctDifference, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } +Slic3r::Polygons diff(const Slic3r::Polygons &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset) + { return _clipper(ClipperLib::ctDifference, ClipperUtils::PolygonsProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } Slic3r::Polygons diff(const Slic3r::ExPolygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset) { return _clipper(ClipperLib::ctDifference, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } Slic3r::Polygons diff(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset) diff --git a/src/libslic3r/ClipperUtils.hpp b/src/libslic3r/ClipperUtils.hpp index fc9677d8b..061658086 100644 --- a/src/libslic3r/ClipperUtils.hpp +++ b/src/libslic3r/ClipperUtils.hpp @@ -296,6 +296,7 @@ Slic3r::Lines _clipper_ln(ClipperLib::ClipType clipType, const Slic3r::Lines &su // Safety offset is applied to the clipping polygons only. Slic3r::Polygons diff(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No); +Slic3r::Polygons diff(const Slic3r::Polygons &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No); Slic3r::Polygons diff(const Slic3r::ExPolygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No); Slic3r::Polygons diff(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No); Slic3r::ExPolygons diff_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No); diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 018754bc0..e68eb7b6d 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -561,7 +561,7 @@ ModelObject& ModelObject::assign_copy(const ModelObject &rhs) this->sla_support_points = rhs.sla_support_points; this->sla_points_status = rhs.sla_points_status; this->sla_drain_holes = rhs.sla_drain_holes; - this->layer_config_ranges = rhs.layer_config_ranges; // #ys_FIXME_experiment + this->layer_config_ranges = rhs.layer_config_ranges; this->layer_height_profile = rhs.layer_height_profile; this->printable = rhs.printable; this->origin_translation = rhs.origin_translation; @@ -602,7 +602,7 @@ ModelObject& ModelObject::assign_copy(ModelObject &&rhs) this->sla_support_points = std::move(rhs.sla_support_points); this->sla_points_status = std::move(rhs.sla_points_status); this->sla_drain_holes = std::move(rhs.sla_drain_holes); - this->layer_config_ranges = std::move(rhs.layer_config_ranges); // #ys_FIXME_experiment + this->layer_config_ranges = std::move(rhs.layer_config_ranges); this->layer_height_profile = std::move(rhs.layer_height_profile); this->origin_translation = std::move(rhs.origin_translation); m_bounding_box = std::move(rhs.m_bounding_box); diff --git a/src/libslic3r/PrintApply.cpp b/src/libslic3r/PrintApply.cpp index 6b6b94f7d..46af1fee8 100644 --- a/src/libslic3r/PrintApply.cpp +++ b/src/libslic3r/PrintApply.cpp @@ -645,31 +645,28 @@ bool verify_update_print_object_regions( } // Verify and / or update PrintRegions produced by color painting. - for (const PrintObjectRegions::LayerRangeRegions &layer_range : print_object_regions.layer_ranges) { - size_t painted_region_idx = 0; - for (unsigned int painted_extruder_id : painting_extruders) - for (int parent_region_id = 0; parent_region_id < int(layer_range.volume_regions.size()); ++ parent_region_id) { - const PrintObjectRegions::VolumeRegion &parent_region = layer_range.volume_regions[parent_region_id]; - const PrintObjectRegions::PaintedRegion ®ion = layer_range.painted_regions[painted_region_idx ++]; - PrintRegionConfig cfg = parent_region.region->config(); - cfg.perimeter_extruder.value = painted_extruder_id; - cfg.infill_extruder.value = painted_extruder_id; - if (cfg != region.region->config()) { - // Region configuration changed. - if (print_region_ref_cnt(*region.region) == 0) { - // Region is referenced for the first time. Just change its parameters. - // Stop the background process before assigning new configuration to the regions. - t_config_option_keys diff = region.region->config().diff(cfg); - callback_invalidate(region.region->config(), cfg, diff); - region.region->config_apply_only(cfg, diff, false); - } else { - // Region is referenced multiple times, thus the region is being split. We need to reslice. - return false; - } + for (const PrintObjectRegions::LayerRangeRegions &layer_range : print_object_regions.layer_ranges) + for (const PrintObjectRegions::PaintedRegion ®ion : layer_range.painted_regions) { + const PrintObjectRegions::VolumeRegion &parent_region = layer_range.volume_regions[region.parent]; + PrintRegionConfig cfg = parent_region.region->config(); + cfg.perimeter_extruder.value = region.extruder_id; + cfg.solid_infill_extruder.value = region.extruder_id; + cfg.infill_extruder.value = region.extruder_id; + if (cfg != region.region->config()) { + // Region configuration changed. + if (print_region_ref_cnt(*region.region) == 0) { + // Region is referenced for the first time. Just change its parameters. + // Stop the background process before assigning new configuration to the regions. + t_config_option_keys diff = region.region->config().diff(cfg); + callback_invalidate(region.region->config(), cfg, diff); + region.region->config_apply_only(cfg, diff, false); + } else { + // Region is referenced multiple times, thus the region is being split. We need to reslice. + return false; } - print_region_ref_inc(*region.region); } - } + print_region_ref_inc(*region.region); + } // Lastly verify, whether some regions were not merged. { @@ -855,16 +852,23 @@ static PrintObjectRegions* generate_print_object_regions( } // Finally add painting regions. - for (PrintObjectRegions::LayerRangeRegions &layer_range : layer_ranges_regions) + for (PrintObjectRegions::LayerRangeRegions &layer_range : layer_ranges_regions) { for (unsigned int painted_extruder_id : painting_extruders) for (int parent_region_id = 0; parent_region_id < int(layer_range.volume_regions.size()); ++ parent_region_id) if (const PrintObjectRegions::VolumeRegion &parent_region = layer_range.volume_regions[parent_region_id]; parent_region.model_volume->is_model_part() || parent_region.model_volume->is_modifier()) { PrintRegionConfig cfg = parent_region.region->config(); - cfg.perimeter_extruder.value = painted_extruder_id; - cfg.infill_extruder.value = painted_extruder_id; + cfg.perimeter_extruder.value = painted_extruder_id; + cfg.solid_infill_extruder.value = painted_extruder_id; + cfg.infill_extruder.value = painted_extruder_id; layer_range.painted_regions.push_back({ painted_extruder_id, parent_region_id, get_create_region(std::move(cfg))}); } + // Sort the regions by parent region::print_object_region_id() and extruder_id to help the slicing algorithm when applying MMU segmentation. + std::sort(layer_range.painted_regions.begin(), layer_range.painted_regions.end(), [&layer_range](auto &l, auto &r) { + int lid = layer_range.volume_regions[l.parent].region->print_object_region_id(); + int rid = layer_range.volume_regions[r.parent].region->print_object_region_id(); + return lid < rid || (lid == rid && l.extruder_id < r.extruder_id); }); + } return out.release(); } @@ -1049,6 +1053,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ bool solid_or_modifier_differ = model_volume_list_changed(model_object, model_object_new, solid_or_modifier_types); bool supports_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::SUPPORT_BLOCKER) || model_volume_list_changed(model_object, model_object_new, ModelVolumeType::SUPPORT_ENFORCER); + bool mmu_segmentation_differ = model_mmu_segmentation_data_changed(model_object, model_object_new); bool layer_height_ranges_differ = ! layer_height_ranges_equal(model_object.layer_config_ranges, model_object_new.layer_config_ranges, model_object_new.layer_height_profile.empty()); bool model_origin_translation_differ = model_object.origin_translation != model_object_new.origin_translation; auto print_objects_range = print_object_status_db.get_range(model_object); @@ -1056,7 +1061,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ // All PrintObjects in print_objects_range shall point to the same prints_objects_regions model_object_status.print_object_regions = print_objects_range.begin()->print_object->m_shared_regions; model_object_status.print_object_regions->ref_cnt_inc(); - if (solid_or_modifier_differ || model_origin_translation_differ || layer_height_ranges_differ || + if (solid_or_modifier_differ || mmu_segmentation_differ || model_origin_translation_differ || layer_height_ranges_differ || ! model_object.layer_height_profile.timestamp_matches(model_object_new.layer_height_profile)) { // The very first step (the slicing step) is invalidated. One may freely remove all associated PrintObjects. model_object_status.print_object_regions_status = model_origin_translation_differ || layer_height_ranges_differ ? @@ -1075,7 +1080,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ model_object_status.print_object_regions->clear(); // Copy content of the ModelObject including its ID, do not change the parent. model_object.assign_copy(model_object_new); - } else { + } else { model_object_status.print_object_regions_status = ModelObjectStatus::PrintObjectRegionsStatus::Valid; if (supports_differ || model_custom_supports_data_changed(model_object, model_object_new)) { // First stop background processing before shuffling or deleting the ModelVolumes in the ModelObject's list. @@ -1229,7 +1234,6 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ // All regions now have distinct settings. // Check whether applying the new region config defaults we would get different regions, // update regions or create regions from scratch. - const std::vector painting_extruders; for (auto it_print_object = m_objects.begin(); it_print_object != m_objects.end();) { // Find the range of PrintObjects sharing the same associated ModelObject. auto it_print_object_end = it_print_object; @@ -1244,6 +1248,13 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ model_object_status.print_object_regions = print_object_regions; print_object_regions->ref_cnt_inc(); } + std::vector painting_extruders; + if (const auto &volumes = print_object.model_object()->volumes; + std::find_if(volumes.begin(), volumes.end(), [](const ModelVolume *v) { return ! v->mmu_segmentation_facets.empty(); }) != volumes.end()) { + //FIXME be more specific! Don't enumerate extruders that are not used for painting! + painting_extruders.assign(num_extruders, 0); + std::iota(painting_extruders.begin(), painting_extruders.end(), 1); + } if (model_object_status.print_object_regions_status == ModelObjectStatus::PrintObjectRegionsStatus::Valid) { // Verify that the trafo for regions & volume bounding boxes thus for regions is still applicable. if (print_object_regions && ! trafos_differ_in_rotation_by_z_and_mirroring_by_xy_only(print_object_regions->trafo_bboxes, model_object_status.print_instances.front().trafo)) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index df635a249..e69edd051 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -6,7 +6,6 @@ #include "Geometry.hpp" #include "I18N.hpp" #include "Layer.hpp" -#include "MultiMaterialSegmentation.hpp" #include "SupportMaterial.hpp" #include "Surface.hpp" #include "Slicing.hpp" diff --git a/src/libslic3r/PrintObjectSlice.cpp b/src/libslic3r/PrintObjectSlice.cpp index a64cedd03..f44d6fdbf 100644 --- a/src/libslic3r/PrintObjectSlice.cpp +++ b/src/libslic3r/PrintObjectSlice.cpp @@ -1,6 +1,7 @@ #include "ElephantFootCompensation.hpp" #include "I18N.hpp" #include "Layer.hpp" +#include "MultiMaterialSegmentation.hpp" #include "Print.hpp" #include @@ -221,10 +222,34 @@ static inline VolumeSlices& volume_slices_find_by_id(std::vector & static inline bool overlap_in_xy(const BoundingBoxf3 &l, const BoundingBoxf3 &r) { + assert(l.defined && r.defined); return ! (l.max.x() < r.min.x() || l.min.x() > r.max.x() || l.max.y() < r.min.y() || l.min.y() > r.max.y()); } +static std::vector::const_iterator layer_range_first(const std::vector &layer_ranges, double z) +{ + auto it = lower_bound_by_predicate(layer_ranges.begin(), layer_ranges.end(), + [z](const PrintObjectRegions::LayerRangeRegions &lr) { return lr.layer_height_range.second < z; }); + assert(it != layer_ranges.end() && it->layer_height_range.first <= z && z <= it->layer_height_range.second); + if (z == it->layer_height_range.second) + if (auto it_next = it; ++ it_next != layer_ranges.end() && it_next->layer_height_range.first == z) + it = it_next; + assert(it != layer_ranges.end() && it->layer_height_range.first <= z && z <= it->layer_height_range.second); + return it; +} + +static std::vector::const_iterator layer_range_next( + const std::vector &layer_ranges, + std::vector::const_iterator it, + double z) +{ + for (; it->layer_height_range.second <= z; ++ it) + assert(it != layer_ranges.end()); + assert(it != layer_ranges.end() && it->layer_height_range.first <= z && z < it->layer_height_range.second); + return it; +} + static std::vector> slices_to_regions( ModelVolumePtrs model_volumes, const PrintObjectRegions &print_object_regions, @@ -304,13 +329,7 @@ static std::vector> slices_to_regions( [&slices_by_region, &print_object_regions, &zs_complex, &layer_ranges_regions_to_slices, clip_multipart_objects, &throw_on_cancel_callback] (const tbb::blocked_range &range) { float z = zs_complex[range.begin()].second; - auto it_layer_range = lower_bound_by_predicate(print_object_regions.layer_ranges.begin(), print_object_regions.layer_ranges.end(), - [z](const PrintObjectRegions::LayerRangeRegions &lr){ return lr.layer_height_range.second < z; }); - assert(it_layer_range != print_object_regions.layer_ranges.end() && it_layer_range->layer_height_range.first <= z && z <= it_layer_range->layer_height_range.second); - if (z == it_layer_range->layer_height_range.second) - if (auto it_next = it_layer_range; ++ it_next != print_object_regions.layer_ranges.end() && it_next->layer_height_range.first == z) - it_layer_range = it_next; - assert(it_layer_range != print_object_regions.layer_ranges.end() && it_layer_range->layer_height_range.first <= z && z <= it_layer_range->layer_height_range.second); + auto it_layer_range = layer_range_first(print_object_regions.layer_ranges, z); // Per volume_regions slices at this Z height. struct RegionSlice { ExPolygons expolygons; @@ -328,9 +347,7 @@ static std::vector> slices_to_regions( std::vector temp_slices; for (size_t zs_complex_idx = range.begin(); zs_complex_idx < range.end(); ++ zs_complex_idx) { auto [z_idx, z] = zs_complex[zs_complex_idx]; - for (; it_layer_range->layer_height_range.second <= z; ++ it_layer_range) - assert(it_layer_range != print_object_regions.layer_ranges.end()); - assert(it_layer_range != print_object_regions.layer_ranges.end() && it_layer_range->layer_height_range.first <= z && z < it_layer_range->layer_height_range.second); + it_layer_range = layer_range_next(print_object_regions.layer_ranges, it_layer_range, z); const PrintObjectRegions::LayerRangeRegions &layer_range = *it_layer_range; { std::vector &layer_range_regions_to_slices = layer_ranges_regions_to_slices[it_layer_range - print_object_regions.layer_ranges.begin()]; @@ -575,57 +592,6 @@ void PrintObject::slice_volumes() } region_slices.clear(); -#if 0 - // Second clip the volumes in the order they are presented at the user interface. - BOOST_LOG_TRIVIAL(debug) << "Slicing volumes - parallel clipping - start"; - tbb::parallel_for( - tbb::blocked_range(0, slice_zs.size()), - [this, &sliced_volumes, num_modifiers](const tbb::blocked_range& range) { - float delta = float(scale_(m_config.xy_size_compensation.value)); - // Only upscale together with clipping if there are no modifiers, as the modifiers shall be applied before upscaling - // (upscaling may grow the object outside of the modifier mesh). - bool upscale = delta > 0 && num_modifiers == 0; - for (size_t layer_id = range.begin(); layer_id < range.end(); ++ layer_id) { - m_print->throw_if_canceled(); - // Trim volumes in a single layer, one by the other, possibly apply upscaling. - { - Polygons processed; - for (SlicedVolume &sliced_volume : sliced_volumes) - if (! sliced_volume.expolygons_by_layer.empty()) { - ExPolygons slices = std::move(sliced_volume.expolygons_by_layer[layer_id]); - if (upscale) - slices = offset_ex(std::move(slices), delta); - if (! processed.empty()) - // Trim by the slices of already processed regions. - slices = diff_ex(slices, processed); - if (size_t(&sliced_volume - &sliced_volumes.front()) + 1 < sliced_volumes.size()) - // Collect the already processed regions to trim the to be processed regions. - polygons_append(processed, slices); - sliced_volume.expolygons_by_layer[layer_id] = std::move(slices); - } - } - // Collect and union volumes of a single region. - for (int region_id = 0; region_id < int(m_region_volumes.size()); ++ region_id) { - ExPolygons expolygons; - size_t num_volumes = 0; - for (SlicedVolume &sliced_volume : sliced_volumes) - if (sliced_volume.region_id == region_id && ! sliced_volume.expolygons_by_layer.empty() && ! sliced_volume.expolygons_by_layer[layer_id].empty()) { - ++ num_volumes; - append(expolygons, std::move(sliced_volume.expolygons_by_layer[layer_id])); - } - if (num_volumes > 1) - // Merge the islands using a positive / negative offset. - expolygons = offset_ex(offset_ex(expolygons, float(scale_(EPSILON))), -float(scale_(EPSILON))); - m_layers[layer_id]->regions()[region_id]->slices.append(std::move(expolygons), stInternal); - } - } - }); - BOOST_LOG_TRIVIAL(debug) << "Slicing volumes - parallel clipping - end"; - clipped = true; - upscaled = m_config.xy_size_compensation.value > 0 && num_modifiers == 0; - } -#endif - BOOST_LOG_TRIVIAL(debug) << "Slicing volumes - removing top empty layers"; while (! m_layers.empty()) { const Layer *layer = m_layers.back(); @@ -638,6 +604,124 @@ void PrintObject::slice_volumes() m_layers.back()->upper_layer = nullptr; m_print->throw_if_canceled(); + // Is any ModelVolume MMU painted? + if (const auto &volumes = this->model_object()->volumes; + std::find_if(volumes.begin(), volumes.end(), [](const ModelVolume *v) { return ! v->mmu_segmentation_facets.empty(); }) != volumes.end()) { + BOOST_LOG_TRIVIAL(debug) << "Slicing volumes - MMU segmentation"; + // Returns MMU segmentation based on painting in MMU segmentation gizmo + std::vector>> segmentation = multi_material_segmentation_by_painting(*this); + assert(segmentation.size() == m_layers.size()); + tbb::parallel_for( + tbb::blocked_range(0, segmentation.size(), std::max(segmentation.size() / 128, size_t(1))), + [this, &segmentation](const tbb::blocked_range &range) { + const auto &layer_ranges = this->m_shared_regions->layer_ranges; + double z = m_layers[range.begin()]->slice_z; + auto it_layer_range = layer_range_first(layer_ranges, z); + const size_t num_extruders = this->print()->config().nozzle_diameter.size(); + struct ByExtruder { + ExPolygons expolygons; + BoundingBox bbox; + }; + std::vector by_extruder; + struct ByRegion { + ExPolygons expolygons; + bool needs_merge { false }; + }; + std::vector by_region; + for (size_t layer_id = range.begin(); layer_id < range.end(); ++ layer_id) { + m_print->throw_if_canceled(); + Layer *layer = m_layers[layer_id]; + it_layer_range = layer_range_next(layer_ranges, it_layer_range, layer->slice_z); + const PrintObjectRegions::LayerRangeRegions &layer_range = *it_layer_range; + // Gather per extruder expolygons. + by_extruder.assign(num_extruders, ByExtruder()); + by_region.assign(layer->m_regions.size(), ByRegion()); + bool layer_split = false; + for (size_t extruder_id = 0; extruder_id < num_extruders; ++ extruder_id) { + ByExtruder ®ion = by_extruder[extruder_id]; + for (const std::pair &colored_polygon : segmentation[layer_id]) + if (colored_polygon.second == extruder_id) + region.expolygons.emplace_back(std::move(colored_polygon.first)); + if (! region.expolygons.empty()) { + region.bbox = get_extents(region.expolygons); + layer_split = true; + } + } + if (! layer_split) + continue; + // Split LayerRegions by by_extruder regions. + auto it_painted_region = layer_range.painted_regions.begin(); + for (size_t region_id = 0; region_id < layer->m_regions.size(); ++ region_id) + if (LayerRegion &layerm = *layer->m_regions[region_id]; ! layerm.slices.surfaces.empty()) { + const BoundingBox bbox = get_extents(layerm.slices.surfaces); + assert(it_painted_region < layer_range.painted_regions.end()); + for (; layer_range.volume_regions[it_painted_region->parent].region->print_object_region_id() < region_id; ++ it_painted_region) + assert(it_painted_region < layer_range.painted_regions.end()); + assert(&layerm.region() == it_painted_region->region && layerm.region().print_object_region_id() == region_id); + // 1-based extruder ID + bool self_trimmed = false; + size_t self_extruder_id; + for (size_t extruder_id = 1; extruder_id <= by_extruder.size(); ++ extruder_id) + if (ByExtruder &segmented = by_extruder[extruder_id - 1]; segmented.bbox.defined && bbox.overlap(segmented.bbox)) { + // Find the target region. + for (; it_painted_region->extruder_id < extruder_id; ++ it_painted_region) + assert(it_painted_region < layer_range.painted_regions.end()); + assert(layer_range.volume_regions[it_painted_region->parent].region == &layerm.region() && it_painted_region->extruder_id == extruder_id); + //FIXME Don't trim by self, it is not reliable. + if (&layerm.region() == it_painted_region->region) { + self_extruder_id = extruder_id; + continue; + } + // Steal from this region. + int target_region_id = it_painted_region->region->print_object_region_id(); + ExPolygons stolen = intersection_ex(layerm.slices.surfaces, segmented.expolygons); + if (! stolen.empty()) { + ByRegion &dst = by_region[target_region_id]; + if (dst.expolygons.empty()) { + dst.expolygons = std::move(stolen); + } else { + append(dst.expolygons, std::move(stolen)); + dst.needs_merge = true; + } + } +#if 0 + if (&layerm.region() == it_painted_region->region) + // Slices of this LayerRegion were trimmed by a MMU region of the same PrintRegion. + self_trimmed = true; +#endif + } + if (! self_trimmed) { + // Trim slices of this LayerRegion with all the MMU regions. + Polygons mine = to_polygons(std::move(layerm.slices.surfaces)); + for (auto &segmented : by_extruder) + if (&segmented - by_extruder.data() + 1 != self_extruder_id && segmented.bbox.defined && bbox.overlap(segmented.bbox)) { + mine = diff(mine, segmented.expolygons); + if (mine.empty()) + break; + } + if (! mine.empty()) { + ByRegion &dst = by_region[layerm.region().print_object_region_id()]; + if (dst.expolygons.empty()) { + dst.expolygons = union_ex(mine); + } else { + append(dst.expolygons, union_ex(mine)); + dst.needs_merge = true; + } + } + } + } + // Re-create Surfaces of LayerRegions. + for (size_t region_id = 0; region_id < layer->m_regions.size(); ++ region_id) { + ByRegion &src = by_region[region_id]; + if (src.needs_merge) + // Multiple regions were merged into one. + src.expolygons = offset2_ex(src.expolygons, float(scale_(EPSILON)), - float(scale_(EPSILON))); + layer->m_regions[region_id]->slices.set(std::move(src.expolygons), stInternal); + } + } + }); + } + BOOST_LOG_TRIVIAL(debug) << "Slicing volumes - make_slices in parallel - begin"; { // Compensation value, scaled. Only applying the negative scaling here, as the positive scaling has already been applied during slicing. @@ -650,8 +734,7 @@ void PrintObject::slice_volumes() ExPolygons lslices_1st_layer; tbb::parallel_for( tbb::blocked_range(0, m_layers.size()), - [this, xy_compensation_scaled, elephant_foot_compensation_scaled, &lslices_1st_layer] - (const tbb::blocked_range& range) { + [this, xy_compensation_scaled, elephant_foot_compensation_scaled, &lslices_1st_layer](const tbb::blocked_range& range) { for (size_t layer_id = range.begin(); layer_id < range.end(); ++ layer_id) { m_print->throw_if_canceled(); Layer *layer = m_layers[layer_id];