diff --git a/src/libslic3r/BridgeDetector.hpp b/src/libslic3r/BridgeDetector.hpp index bb1c1ead3d..bc5da9712f 100644 --- a/src/libslic3r/BridgeDetector.hpp +++ b/src/libslic3r/BridgeDetector.hpp @@ -126,12 +126,6 @@ inline std::tuple detect_bridging_direction(const Polygons &to_co }; -inline Vec2d detect_internal_bridge_direction() { - //TODO AABB tree, get nearest point on the infill polylines (or perimeters) and do not take duplicates - // this could yield some density map where the more scattered points are more interesting -} - - } #endif diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index ab8fa5dd93..1c9ea6a985 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -1,6 +1,11 @@ +#include "AABBTreeLines.hpp" +#include "BridgeDetector.hpp" +#include "ExPolygon.hpp" #include "Exception.hpp" #include "KDTreeIndirect.hpp" #include "Point.hpp" +#include "Polygon.hpp" +#include "Polyline.hpp" #include "Print.hpp" #include "BoundingBox.hpp" #include "ClipperUtils.hpp" @@ -1530,7 +1535,6 @@ void PrintObject::bridge_over_infill() tbb::parallel_for(tbb::blocked_range(0, this->layers().size()), [po = this](tbb::blocked_range r) { for (size_t lidx = r.begin(); lidx < r.end(); lidx++) { - const Layer *layer = po->get_layer(lidx); // gather also sparse infill surfaces on this layer, to which we can expand the bridges for anchoring @@ -1539,6 +1543,7 @@ void PrintObject::bridge_over_infill() std::unordered_map bridging_surface_candidates; std::unordered_map expansion_space; std::unordered_map max_bridge_flow_height; + std::unordered_map max_bridge_flow_width; for (const LayerSlice &slice : layer->lslices_ex) { std::unordered_set regions_to_check; for (const LayerIsland &island : slice.islands) { @@ -1552,8 +1557,10 @@ void PrintObject::bridge_over_infill() const LayerRegion *region = layer->get_region(region_idx); auto region_internal_solids = region->fill_surfaces().filter_by_type(stInternalSolid); if (!region_internal_solids.empty()) { - max_bridge_flow_height[&slice] = std::max(max_bridge_flow_height[&slice], - region->bridging_flow(frSolidInfill).height()); + max_bridge_flow_height[&slice] = std::max(max_bridge_flow_height[&slice], + region->bridging_flow(frSolidInfill).height()); + max_bridge_flow_width[&slice] = std::max(max_bridge_flow_width[&slice], + region->bridging_flow(frSolidInfill).width()); } bridging_surface_candidates[&slice].insert(bridging_surface_candidates[&slice].end(), region_internal_solids.begin(), region_internal_solids.end()); @@ -1562,33 +1569,15 @@ void PrintObject::bridge_over_infill() } } - for (const std::pair &candidates : bridging_surface_candidates) { - if (candidates.second.empty()) { - continue; - }; - - // Gather lower layers sparse infill areas, to depth defined by used bridge flow - Polygons lower_layers_sparse_infill; - double bottom_z = layer->print_z - max_bridge_flow_height[candidates.first] - EPSILON; - LayerSlice::Links current_links = candidates.first->overlaps_below; - for (auto i = int(lidx) - 1; i >= 0; --i) { - // Stop iterating if layer is lower than bottom_z. - if (po->get_layer(i)->print_z < bottom_z) - break; - for (const auto &link : current_links) { - const LayerSlice& slice_below = po->get_layer(i)->lslices_ex[link.slice_idx]; - for (const LayerRegion *region : po->get_layer(i)->regions()) { - for (const Surface *surface : region->fill_surfaces().filter_by_type(stInternal)) { - Polygons p = to_polygons(surface->expolygon); - lower_layers_sparse_infill.insert(lower_layers_sparse_infill.end(), p.begin(), p.end()); - } - } - } - } - lower_layers_sparse_infill = union_(lower_layers_sparse_infill); + // if there are none briding candidates, exit now, before making infill for the previous layer + if (std::all_of(bridging_surface_candidates.begin(), bridging_surface_candidates.end(), + [](const std::pair &candidates) { return candidates.second.empty(); })) { + continue; } // Now, temporarily fill the previous layer and extract the extrusions. + // TODO - the make_fills function does a lot of work, some of it is not needed (e.g. sorting the paths) + // It would be nice to have a function that only creates the fill polylines, ideally without modifying the global state po->get_layer(lidx)->lower_layer->make_fills(nullptr, nullptr, nullptr); Polylines lower_layer_polylines; for (const LayerRegion *region : layer->lower_layer->m_regions) { @@ -1598,15 +1587,128 @@ void PrintObject::bridge_over_infill() lower_layer_polylines.insert(lower_layer_polylines.end(), region_polylines.begin(), region_polylines.end()); } } - } + + for (const std::pair candidates : bridging_surface_candidates) { + if (candidates.second.empty()) { + continue; + }; + + // Gather lower layers sparse infill areas, to depth defined by used bridge flow + Polygons lower_layers_sparse_infill; + double bottom_z = layer->print_z - max_bridge_flow_height[candidates.first] - EPSILON; + LayerSlice::Links current_links = candidates.first->overlaps_below; + LayerSlice::Links next_links{}; + for (auto i = int(lidx) - 1; i >= 0; --i) { + // Stop iterating if layer is lower than bottom_z. + if (po->get_layer(i)->print_z < bottom_z) + break; + for (const auto &link : current_links) { + const LayerSlice &slice_below = po->get_layer(i)->lslices_ex[link.slice_idx]; + next_links.insert(next_links.end(), slice_below.overlaps_below.begin(), slice_below.overlaps_below.end()); + std::unordered_set regions_under_to_check; + for (const LayerIsland &island : slice_below.islands) { + regions_under_to_check.insert(island.perimeters.region()); + if (!island.fill_expolygons_composite()) { + regions_under_to_check.insert(island.fill_region_id); + } + } + + for (size_t region_idx : regions_under_to_check) { + const LayerRegion *region = layer->get_region(region_idx); + for (const Surface *surface : region->fill_surfaces().filter_by_type(stInternal)) { + Polygons p = to_polygons(surface->expolygon); + lower_layers_sparse_infill.insert(lower_layers_sparse_infill.end(), p.begin(), p.end()); + } + } + } + current_links = next_links; + } + if (lower_layers_sparse_infill.empty()) { + continue; + } + lower_layers_sparse_infill = union_(lower_layers_sparse_infill); + + Polygons expand_area; + for (const Surface *sparse_infill : expansion_space[candidates.first]) { + assert(sparse_infill->surface_type == stInternal); + Polygons a = to_polygons(sparse_infill->expolygon); + expand_area.insert(expand_area.end(), a.begin(), a.end()); + } + + // Lower layers sparse infill sections gathered + // now we can intersected them with bridging surface candidates to get actual areas that need and can accumulate + // bridging. These areas we then expand (within the surrounding sparse infill only!) + // to touch the infill polylines on previous layer. + for (const Surface *candidate : candidates.second) { + assert(candidate->surface_type == stInternalSolid); + Polygons bridged_area = to_polygons(candidate->expolygon); + bridged_area = + intersection(bridged_area, + lower_layers_sparse_infill); // cut off parts which are not over sparse infill - material overflow + + if (bridged_area.empty()) { + continue; + } + + Polygons max_area = expand_area; + max_area.insert(max_area.end(), bridged_area.begin(), bridged_area.end()); + closing(max_area, max_bridge_flow_width[candidates.first]); + + Polylines anchors = intersection_pl(lower_layer_polylines, max_area); + anchors = diff_pl(anchors, shrink(bridged_area, scale_(max_bridge_flow_width[candidates.first]))); + + AABBTreeLines::LinesDistancer anchors_and_walls; + { + Lines tmp = to_lines(anchors); + Lines tmp2 = to_lines(max_area); + tmp.insert(tmp.end(), tmp.begin(), tmp.end()); + anchors_and_walls = AABBTreeLines::LinesDistancer{tmp}; + } + + double bridging_dir = 0; + { + std::vector> directions_with_distances; + for (const Polygon &p : bridged_area) { + for (int point_idx = 0; point_idx < int(p.points.size()) - 1; ++point_idx) { + Vec2d start = p.points[point_idx].cast(); + Vec2d next = p.points[point_idx + 1].cast(); + Vec2d v = next - start; // vector from next to current + double dist_to_next = v.norm(); + v.normalize(); + int lines_count = int(std::ceil(dist_to_next / scaled(3.0))); + float step_size = dist_to_next / lines_count; + for (int i = 0; i < lines_count; ++i) { + Point a(start + v * (i * step_size)); + auto [distance, index, p] = anchors_and_walls.distance_from_lines_extra(a); + const Line& l = anchors_and_walls.get_line(index); + directions_with_distances.emplace_back(l.direction(), unscaled(distance)); + } + } + } + double max_dist = directions_with_distances[0].second; + for (const auto& dir :directions_with_distances) { + max_dist = std::max(max_dist, dir.second); + } + double acc = 0; + for (const auto& dir : directions_with_distances) { + bridging_dir += dir.first * (max_dist - dir.second); + acc += (max_dist - dir.second); + } + bridging_dir /= acc; + } + + + + } // surface iteration end + } // island iteration end + } // layer iteration end }); BOOST_LOG_TRIVIAL(info) << "Bridge over infill - End" << log_memory_info(); +} // void PrintObject::bridge_over_infill() - - - +void a(){ 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().fill_density.value < 100) @@ -1731,6 +1833,7 @@ void PrintObject::bridge_over_infill() m_print->throw_if_canceled(); } }); + } // void PrintObject::bridge_over_infill() static void clamp_exturder_to_default(ConfigOptionInt &opt, size_t num_extruders)