From a91a7d6b0e32bb6e446175f33e5ecd324537c07c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20=C5=A0ach?= Date: Tue, 11 Jun 2024 16:10:24 +0200 Subject: [PATCH] Better detection of bridge orientation. Before, partial bridges were calculated. For each of these an angle has been choosen and after that all the bridges have been merged. Becouse of the merge a single angle had to be picked. The first angle that the algorithm has stumbled upon has been picked, resulting in sub-optimal bridging directions. Now the partial bridges are calcualted, then merged and then the angle is decided over the whole merged bridge. This approach at least ensures that the orientation is the best possible for the merged bridge. --- src/libslic3r/LayerRegion.cpp | 78 ++++++--------------------- tests/libslic3r/test_layer_region.cpp | 2 +- 2 files changed, 17 insertions(+), 63 deletions(-) diff --git a/src/libslic3r/LayerRegion.cpp b/src/libslic3r/LayerRegion.cpp index 94c5d4fbb6..a2067dfc6b 100644 --- a/src/libslic3r/LayerRegion.cpp +++ b/src/libslic3r/LayerRegion.cpp @@ -198,7 +198,6 @@ struct Bridge { ExPolygon expolygon; uint32_t group_id; std::vector::const_iterator bridge_expansion_begin; - std::optional angle{std::nullopt}; }; // Group the bridge surfaces by overlaps. @@ -282,54 +281,6 @@ std::vector get_grouped_bridges( return result; } -void detect_bridge_directions( - const Algorithm::WaveSeeds& bridge_anchors, - std::vector& bridges, - const std::vector& expansion_zones -) { - if (expansion_zones.empty()) { - throw std::runtime_error("At least one expansion zone must exist!"); - } - auto it_bridge_anchor = bridge_anchors.begin(); - for (uint32_t bridge_id = 0; bridge_id < uint32_t(bridges.size()); ++ bridge_id) { - Bridge &bridge = bridges[bridge_id]; - Polygons anchor_areas; - int32_t last_anchor_id = -1; - for (; it_bridge_anchor != bridge_anchors.end() && it_bridge_anchor->src == bridge_id; ++ it_bridge_anchor) { - if (last_anchor_id != int(it_bridge_anchor->boundary)) { - last_anchor_id = int(it_bridge_anchor->boundary); - - unsigned start_index{}; - unsigned end_index{}; - for (const ExpansionZone& expansion_zone: expansion_zones) { - end_index += expansion_zone.expolygons.size(); - if (last_anchor_id < static_cast(end_index)) { - append(anchor_areas, to_polygons(expansion_zone.expolygons[last_anchor_id - start_index])); - break; - } - start_index += expansion_zone.expolygons.size(); - } - } - } - Lines lines{to_lines(diff_pl(to_polylines(bridge.expolygon), expand(anchor_areas, float(SCALED_EPSILON))))}; - auto [bridging_dir, unsupported_dist] = detect_bridging_direction(lines, to_polygons(bridge.expolygon)); - bridge.angle = M_PI + std::atan2(bridging_dir.y(), bridging_dir.x()); - - if constexpr (false) { - coordf_t stroke_width = scale_(0.06); - BoundingBox bbox = get_extents(anchor_areas); - bbox.merge(get_extents(bridge.expolygon)); - bbox.offset(scale_(1.)); - ::Slic3r::SVG - svg(debug_out_path(("bridge" + std::to_string(*bridge.angle) + "_" /* + std::to_string(this->layer()->bottom_z())*/).c_str()), - bbox); - svg.draw(bridge.expolygon, "cyan"); - svg.draw(lines, "green", stroke_width); - svg.draw(anchor_areas, "red"); - } - } -} - Surfaces merge_bridges( std::vector& bridges, const std::vector& bridge_expansions, @@ -345,29 +296,33 @@ Surfaces merge_bridges( for (uint32_t bridge_id = 0; bridge_id < uint32_t(bridges.size()); ++ bridge_id) { if (group_id(bridges, bridge_id) == bridge_id) { // Head of the group. - Polygons acc; - for (uint32_t bridge_id2 = bridge_id; bridge_id2 < uint32_t(bridges.size()); ++ bridge_id2) + Polygons bridge_group; + Polygons expansions; + for (uint32_t bridge_id2 = bridge_id; bridge_id2 < uint32_t(bridges.size()); ++ bridge_id2) { if (group_id(bridges, bridge_id2) == bridge_id) { - append(acc, to_polygons(std::move(bridges[bridge_id2].expolygon))); + append(bridge_group, to_polygons(std::move(bridges[bridge_id2].expolygon))); auto it_bridge_expansion = bridges[bridge_id2].bridge_expansion_begin; assert(it_bridge_expansion == bridge_expansions.end() || it_bridge_expansion->src_id == bridge_id2); for (; it_bridge_expansion != bridge_expansions.end() && it_bridge_expansion->src_id == bridge_id2; ++ it_bridge_expansion) - append(acc, to_polygons(it_bridge_expansion->expolygon)); + append(expansions, to_polygons(it_bridge_expansion->expolygon)); } - //FIXME try to be smart and pick the best bridging angle for all? - if (!bridges[bridge_id].angle) { - assert(false && "Bridge angle must be pre-calculated!"); } - Surface templ{ stBottomBridge, {} }; - templ.bridge_angle = bridges[bridge_id].angle ? *bridges[bridge_id].angle : -1; + append(bridge_group, expansions); + //NOTE: The current regularization of the shells can create small unasigned regions in the object (E.G. benchy) // without the following closing operation, those regions will stay unfilled and cause small holes in the expanded surface. // look for narrow_ensure_vertical_wall_thickness_region_radius filter. - ExPolygons final = closing_ex(acc, closing_radius); + ExPolygons merged_bridges = closing_ex(bridge_group, closing_radius); // without safety offset, artifacts are generated (GH #2494) // union_safety_offset_ex(acc) - for (ExPolygon &ex : final) - result.emplace_back(templ, std::move(ex)); + + for (ExPolygon &bridge_expolygon : merged_bridges) { + Surface surface{ stBottomBridge, std::move(bridge_expolygon) }; + const Lines lines{to_lines(diff_pl(to_polylines(bridge_expolygon), expand(expansions, float(SCALED_EPSILON))))}; + auto [bridging_dir, unsupported_dist] = detect_bridging_direction(lines, to_polygons(bridge_expolygon)); + surface.bridge_angle = M_PI + std::atan2(bridging_dir.y(), bridging_dir.x()); + result.push_back(std::move(surface)); + } } } return result; @@ -444,7 +399,6 @@ Surfaces expand_bridges_detect_orientations( bridge_expolygons.clear(); std::sort(expansion_result.anchors.begin(), expansion_result.anchors.end(), Algorithm::lower_by_src_and_boundary); - detect_bridge_directions(expansion_result.anchors, bridges, expansion_zones); // Merge the groups with the same group id, produce surfaces by merging source overhangs with their newly expanded anchors. std::sort(expansion_result.expansions.begin(), expansion_result.expansions.end(), [](auto &l, auto &r) { diff --git a/tests/libslic3r/test_layer_region.cpp b/tests/libslic3r/test_layer_region.cpp index 0f6dfb7cba..1351b8a6e4 100644 --- a/tests/libslic3r/test_layer_region.cpp +++ b/tests/libslic3r/test_layer_region.cpp @@ -131,7 +131,7 @@ TEST_CASE_METHOD(LayerRegionFixture, "test the bridge expansion with the bridge } REQUIRE(result.size() == 2); - CHECK(result.at(0).bridge_angle == Approx(1.5707963268)); + CHECK(std::fmod(result.at(1).bridge_angle, M_PI) == Approx(0.0)); CHECK(std::fmod(result.at(1).bridge_angle, M_PI) == Approx(0.0)); CHECK(result.at(0).expolygon.contour.size() == 22); CHECK(result.at(1).expolygon.contour.size() == 14);