diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index f39732b173..e3b089ca6e 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -1728,61 +1728,70 @@ void PrintObject::discover_vertical_shells() // PROFILE_OUTPUT(debug_out_path("discover_vertical_shells-profile.txt").c_str()); } -/* This method applies bridge flow to the first internal solid layer above - sparse infill */ +// This method applies bridge flow to the first internal solid layer above sparse infill. void PrintObject::bridge_over_infill() { BOOST_LOG_TRIVIAL(info) << "Bridge over infill..." << log_memory_info(); - for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id) { - const PrintRegion ®ion = this->printing_region(region_id); + std::vector sparse_infill_regions; + for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id) + if (const PrintRegion ®ion = this->printing_region(region_id); region.config().sparse_infill_density.value < 100) + sparse_infill_regions.emplace_back(region_id); + if (this->layer_count() < 2 || sparse_infill_regions.empty()) + return; - // skip bridging in case there are no voids - if (region.config().sparse_infill_density.value == 100) - continue; + // Collect sum of all internal (sparse infill) regions, because + // 1) layerm->fill_surfaces.will be modified in parallel. + // 2) the parallel loop works on a sum of surfaces over regions anyways, thus collecting the sparse infill surfaces + // up front is an optimization. + std::vector internals; + internals.reserve(this->layer_count()); + for (Layer *layer : m_layers) { + Polygons sum; + for (const LayerRegion *layerm : layer->m_regions) + layerm->fill_surfaces.filter_by_type(stInternal, &sum); + internals.emplace_back(std::move(sum)); + } - for (LayerPtrs::iterator layer_it = m_layers.begin(); layer_it != m_layers.end(); ++ layer_it) { - // skip first layer - if (layer_it == m_layers.begin()) - continue; - - Layer *layer = *layer_it; + // Process all regions and layers in parallel. + tbb::parallel_for(tbb::blocked_range(0, sparse_infill_regions.size() * (this->layer_count() - 1), sparse_infill_regions.size()), + [this, &sparse_infill_regions, &internals] + (const tbb::blocked_range &range) { + for (size_t task_id = range.begin(); task_id != range.end(); ++ task_id) { + const size_t layer_id = (task_id / sparse_infill_regions.size()) + 1; + const size_t region_id = sparse_infill_regions[task_id % sparse_infill_regions.size()]; + Layer *layer = this->get_layer(layer_id); LayerRegion *layerm = layer->m_regions[region_id]; const PrintObjectConfig& object_config = layer->object()->config(); //BBS: enable thick bridge for internal bridge only Flow bridge_flow = layerm->bridging_flow(frSolidInfill, true); - // extract the stInternalSolid surfaces that might be transformed into bridges - Polygons internal_solid; - layerm->fill_surfaces.filter_by_type(stInternalSolid, &internal_solid); + // Extract the stInternalSolid surfaces that might be transformed into bridges. + ExPolygons internal_solid; + layerm->fill_surfaces.remove_type(stInternalSolid, &internal_solid); + if (internal_solid.empty()) + // No internal solid -> no new bridges for this layer region. + continue; // check whether the lower area is deep enough for absorbing the extra flow // (for obvious physical reasons but also for preventing the bridge extrudates // from overflowing in 3D preview) ExPolygons to_bridge; { - Polygons to_bridge_pp = internal_solid; - - // iterate through lower layers spanned by bridge_flow + Polygons to_bridge_pp = to_polygons(internal_solid); + // Iterate through lower layers spanned by bridge_flow. double bottom_z = layer->print_z - bridge_flow.height() - EPSILON; - for (int i = int(layer_it - m_layers.begin()) - 1; i >= 0; --i) { - const Layer* lower_layer = m_layers[i]; - - // stop iterating if layer is lower than bottom_z - if (lower_layer->print_z < bottom_z) break; - - // iterate through regions and collect internal surfaces - Polygons lower_internal; - for (LayerRegion *lower_layerm : lower_layer->m_regions) - lower_layerm->fill_surfaces.filter_by_type(stInternal, &lower_internal); - - // intersect such lower internal surfaces with the candidate solid surfaces - to_bridge_pp = intersection(to_bridge_pp, lower_internal); + for (auto i = int(layer_id) - 1; i >= 0; -- i) { + // Stop iterating if layer is lower than bottom_z. + if (m_layers[i]->print_z < bottom_z) + break; + // Intersect lower sparse infills with the candidate solid surfaces. + to_bridge_pp = intersection(to_bridge_pp, internals[i]); } // BBS: expand to make avoid gap between bridge and inner wall to_bridge_pp = expand(to_bridge_pp, bridge_flow.scaled_width()); - to_bridge_pp = intersection(to_bridge_pp, internal_solid); + to_bridge_pp = intersection(to_bridge_pp, to_polygons(internal_solid)); // there's no point in bridging too thin/short regions //FIXME Vojtech: The offset2 function is not a geometric offset, @@ -1793,7 +1802,12 @@ void PrintObject::bridge_over_infill() to_bridge_pp = opening(to_bridge_pp, min_width); } - if (to_bridge_pp.empty()) continue; + if (to_bridge_pp.empty()) { + // Restore internal_solid surfaces. + for (ExPolygon &ex : internal_solid) + layerm->fill_surfaces.surfaces.push_back(Surface(stInternalSolid, std::move(ex))); + continue; + } // convert into ExPolygons to_bridge = union_ex(to_bridge_pp); @@ -1807,7 +1821,6 @@ void PrintObject::bridge_over_infill() ExPolygons not_to_bridge = diff_ex(internal_solid, to_bridge, ApplySafetyOffset::Yes); to_bridge = intersection_ex(to_bridge, internal_solid, ApplySafetyOffset::Yes); // build the new collection of fill_surfaces - layerm->fill_surfaces.remove_type(stInternalSolid); for (ExPolygon &ex : to_bridge) { layerm->fill_surfaces.surfaces.push_back(Surface(stInternalBridge, ex)); // BBS: detect angle for internal bridge infill @@ -1825,8 +1838,8 @@ void PrintObject::bridge_over_infill() float internal_loop_thickness = object_config.internal_bridge_support_thickness.value; double bottom_z = layer->print_z - layer->height - internal_loop_thickness + EPSILON; //BBS: lighting infill doesn't support this feature. Don't need to add loop when infill density is high than 50% - if (region.config().sparse_infill_pattern != InfillPattern::ipLightning && region.config().sparse_infill_density.value < 50) - for (int i = int(layer_it - m_layers.begin()) - 1; i >= 0; --i) { + if (layerm->region().config().sparse_infill_pattern != InfillPattern::ipLightning && layerm->region().config().sparse_infill_density.value < 50) + for (int i = layer_id - 1; i >= 0; --i) { const Layer* lower_layer = m_layers[i]; if (lower_layer->print_z < bottom_z) break; @@ -1893,7 +1906,7 @@ void PrintObject::bridge_over_infill() #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */ m_print->throw_if_canceled(); } - } + }); } static void clamp_exturder_to_default(ConfigOptionInt &opt, size_t num_extruders) diff --git a/src/libslic3r/SurfaceCollection.cpp b/src/libslic3r/SurfaceCollection.cpp index f2f0b3f97e..f0af8dcd2d 100644 --- a/src/libslic3r/SurfaceCollection.cpp +++ b/src/libslic3r/SurfaceCollection.cpp @@ -65,7 +65,7 @@ SurfacesPtr SurfaceCollection::filter_by_types(const SurfaceType *types, int nty return ss; } -void SurfaceCollection::filter_by_type(SurfaceType type, Polygons* polygons) +void SurfaceCollection::filter_by_type(SurfaceType type, Polygons* polygons) const { for (const Surface &surface : this->surfaces) if (surface.surface_type == type) @@ -121,6 +121,22 @@ void SurfaceCollection::remove_type(const SurfaceType type) surfaces.erase(surfaces.begin() + j, surfaces.end()); } +void SurfaceCollection::remove_type(const SurfaceType type, ExPolygons *polygons) +{ + size_t j = 0; + for (size_t i = 0; i < surfaces.size(); ++ i) { + if (Surface &surface = surfaces[i]; surface.surface_type == type) { + polygons->emplace_back(std::move(surface.expolygon)); + } else { + if (j < i) + std::swap(surfaces[i], surfaces[j]); + ++ j; + } + } + if (j < surfaces.size()) + surfaces.erase(surfaces.begin() + j, surfaces.end()); +} + void SurfaceCollection::remove_types(const SurfaceType *types, int ntypes) { size_t j = 0; diff --git a/src/libslic3r/SurfaceCollection.hpp b/src/libslic3r/SurfaceCollection.hpp index 50be3e97da..50c71f011f 100644 --- a/src/libslic3r/SurfaceCollection.hpp +++ b/src/libslic3r/SurfaceCollection.hpp @@ -32,7 +32,8 @@ public: void keep_types(const SurfaceType *types, int ntypes); void remove_type(const SurfaceType type); void remove_types(const SurfaceType *types, int ntypes); - void filter_by_type(SurfaceType type, Polygons* polygons); + void filter_by_type(SurfaceType type, Polygons* polygons) const; + void remove_type(const SurfaceType type, ExPolygons *polygons); void set_type(SurfaceType type) { for (Surface &surface : this->surfaces) surface.surface_type = type;