From 6521b722749775b9c7809d38a5b454428e75932f Mon Sep 17 00:00:00 2001
From: PavelMikus <pavel.mikus.mail@seznam.cz>
Date: Wed, 15 Feb 2023 17:23:31 +0100
Subject: [PATCH] Fix problems with adaptive infills, but the anchoring itself
 is not used on them Fix briding angles for octagram and hilberts curve

---
 src/libslic3r/Fill/Fill.cpp   |  8 ++++
 src/libslic3r/PrintObject.cpp | 72 +++++++++++++++++++++++++++--------
 2 files changed, 64 insertions(+), 16 deletions(-)

diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp
index 082cf93cc..043a2e34a 100644
--- a/src/libslic3r/Fill/Fill.cpp
+++ b/src/libslic3r/Fill/Fill.cpp
@@ -442,6 +442,14 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
 #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
 
     for (SurfaceFill &surface_fill : surface_fills) {
+		//skip patterns for which additional input is nullptr
+		switch (surface_fill.params.pattern) {
+			case ipLightning: if (lightning_generator == nullptr) continue; break;
+			case ipAdaptiveCubic: if (adaptive_fill_octree == nullptr) continue; break;
+			case ipSupportCubic: if (support_fill_octree == nullptr) continue; break;
+			default: break;
+		}
+
         // Create the filler object.
         std::unique_ptr<Fill> f = std::unique_ptr<Fill>(Fill::new_from_type(surface_fill.params.pattern));
         f->set_bounding_box(bbox);
diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp
index 63ce832d8..f1f377deb 100644
--- a/src/libslic3r/PrintObject.cpp
+++ b/src/libslic3r/PrintObject.cpp
@@ -1638,6 +1638,17 @@ void PrintObject::bridge_over_infill()
                     continue;
                 }
 
+                auto region_has_anchorable_sparse_infill = [](const LayerRegion* layer_region) {
+                    switch (layer_region->region().config().fill_pattern.value) {
+                    case ipAdaptiveCubic: return false;
+                    case ipSupportCubic: return false;
+                    case ipLightning: return false;
+                    default: break;
+                    }
+
+                    return layer_region->region().config().fill_density.value < 100;
+                };
+
                 // 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;
@@ -1660,7 +1671,7 @@ void PrintObject::bridge_over_infill()
 
                         for (size_t region_idx : regions_under_to_check) {
                             const LayerRegion *region = po->get_layer(i)->get_region(region_idx);
-                            if (region->region().config().fill_density.value < 100) {
+                            if (region_has_anchorable_sparse_infill(region)) {
                                 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());
@@ -1703,7 +1714,7 @@ void PrintObject::bridge_over_infill()
                     closing(max_area, flow.scaled_width());
 
                     Polylines anchors = intersection_pl(lower_layer_polylines, max_area);
-                    anchors           = diff_pl(anchors, shrink(bridged_area, flow.scaled_width()));
+                    anchors           = diff_pl(anchors, bridged_area);
 
                     Lines anchors_and_walls = to_lines(anchors);
                     Lines tmp               = to_lines(max_area);
@@ -1716,9 +1727,9 @@ void PrintObject::bridge_over_infill()
 
                     double bridging_angle = 0;
                     {
-                        AABBTreeLines::LinesDistancer<Line> lines_tree{anchors_and_walls};
+                        AABBTreeLines::LinesDistancer<Line> lines_tree{anchors.empty() ? anchors_and_walls : to_lines(anchors)};
 
-                        std::vector<std::pair<double, double>> directions_with_distances;
+                        std::map<double, int> counted_directions;
                         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<double>();
@@ -1736,23 +1747,52 @@ void PrintObject::bridge_over_infill()
                                         angle -= PI;
                                     }
                                     angle += PI * 0.5;
-                                    directions_with_distances.emplace_back(angle, distance);
+                                    counted_directions[angle]++;
                                 }
                             }
                         }
-                        double max_dist = directions_with_distances[0].second;
-                        for (const auto &dir : directions_with_distances) {
-                            max_dist = std::max(max_dist, dir.second);
+
+                        std::pair<double, int> best_dir{0, 0};
+                        // sliding window accumulation 
+                        for (const auto &dir : counted_directions) {
+                            int    score_acc          = 0;
+                            double dir_acc            = 0;
+                            double window_start_angle = dir.first - PI * 0.2;
+                            double window_end_angle   = dir.first + PI * 0.2;
+                            for (auto dirs_window = counted_directions.lower_bound(window_start_angle);
+                                 dirs_window != counted_directions.upper_bound(window_end_angle); dirs_window++) {
+                                dir_acc += dirs_window->first * dirs_window->second;
+                                score_acc += dirs_window->second;
+                            }
+                            // current span of directions is 0.5 PI to 1.5 PI (due to the aproach.). Edge values should also account for the
+                            //  opposite direction.
+                            if (window_start_angle < 0.5 * PI) {
+                                for (auto dirs_window = counted_directions.lower_bound(1.5 * PI - (0.5 * PI - window_start_angle));
+                                     dirs_window != counted_directions.end(); dirs_window++) {
+                                    dir_acc += dirs_window->first *  dirs_window->second;
+                                    score_acc += dirs_window->second;
+                                }
+                            }
+                            if (window_start_angle > 1.5 * PI) {
+                                for (auto dirs_window = counted_directions.begin();
+                                     dirs_window != counted_directions.upper_bound(window_start_angle - 1.5 * PI); dirs_window++) {
+                                    dir_acc += dirs_window->first *  dirs_window->second;
+                                    score_acc += dirs_window->second;
+                                }
+                            }
+
+                            if (score_acc > best_dir.second) {
+                                best_dir = {dir_acc / score_acc, score_acc};
+                            }
                         }
-                        double acc = 0;
-                        for (const auto &dir : directions_with_distances) {
-                            bridging_angle += dir.first * (max_dist - dir.second);
-                            acc += (max_dist - dir.second);
-                        }
-                        if (acc <= EPSILON || bridging_angle == 0) {
+                        bridging_angle = best_dir.first;
+                        if (bridging_angle == 0) {
                             bridging_angle = 0.001;
-                        } else {
-                            bridging_angle /= acc;
+                        }
+                        switch (surface_to_region[candidate]->region().config().fill_pattern.value) {
+                        case ipHilbertCurve: bridging_angle += 0.25 * PI; break;
+                        case ipOctagramSpiral: bridging_angle += (1.0 / 16.0) * PI; break;
+                        default: break;
                         }
                     }