From cb20051e03bd115a6b081d951a87fdf1a97893d2 Mon Sep 17 00:00:00 2001 From: Filip Sykala - NTB T15p Date: Wed, 19 Feb 2025 00:43:00 +0100 Subject: [PATCH] Fix for creating wide tiny change. + unify runtime by selecting position with smallest source index --- .../SLA/SupportIslands/SupportIslandPoint.cpp | 2 + .../SupportIslands/UniformSupportIsland.cpp | 105 ++++++++++-------- tests/sla_print/sla_supptgen_tests.cpp | 45 ++++---- 3 files changed, 89 insertions(+), 63 deletions(-) diff --git a/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.cpp b/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.cpp index b5ccf5f1dc..dc1282454f 100644 --- a/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.cpp +++ b/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.cpp @@ -39,6 +39,8 @@ std::string SupportIslandPoint::to_string(const Type &type) {Type::thin_part_loop, "thin_part_loop"}, {Type::thick_part_outline, "thick_part_outline"}, {Type::thick_part_inner, "thick_part_inner"}, + {Type::bad_shape_for_vd, "bad_shape_for_vd"}, + {Type::permanent, "permanent"}, {Type::undefined, "undefined"}}; auto it = type_to_string.find(type); if (it == type_to_string.end()) diff --git a/src/libslic3r/SLA/SupportIslands/UniformSupportIsland.cpp b/src/libslic3r/SLA/SupportIslands/UniformSupportIsland.cpp index 00df03fd91..67793d04df 100644 --- a/src/libslic3r/SLA/SupportIslands/UniformSupportIsland.cpp +++ b/src/libslic3r/SLA/SupportIslands/UniformSupportIsland.cpp @@ -431,10 +431,10 @@ coord_t align_once( SupportIslandPointPtr &support = supports[i]; #ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG_PATH - if (!sample->can_move()) { // draww freezed support points - svg.draw(sample->point, color_static_point, config.head_radius); - svg.draw_text(sample->point + Point(config.head_radius, 0), - SupportIslandPoint::to_string(sample->type).c_str(), color_static_point.c_str()); + if (!support->can_move()) { // draww freezed support points + svg.draw(support->point, color_static_point, config.head_radius); + svg.draw_text(support->point + Point(config.head_radius, 0), + SupportIslandPoint::to_string(support->type).c_str(), color_static_point.c_str()); } #endif // SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG_PATH if (!support->can_move()) @@ -488,8 +488,8 @@ coord_t align_once( #ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG_PATH svg.draw(cell_polygon, color_point_cell); svg.draw(*island_cell, color_island_cell_intersection); - svg.draw(Line(sample->point, island_cell_center), color_wanted_point, config.head_radius / 5); - svg.draw(sample->point, color_old_point, config.head_radius); + svg.draw(Line(support->point, island_cell_center), color_wanted_point, config.head_radius / 5); + svg.draw(support->point, color_old_point, config.head_radius); svg.draw(island_cell_center, color_wanted_point, config.head_radius); // wanted position #endif // SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG_PATH @@ -499,9 +499,10 @@ coord_t align_once( max_move = act_move; #ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG_PATH - svg.draw(sample->point, color_new_point, config.head_radius); - svg.draw_text(sample->point + Point(config.head_radius, 0), - SupportIslandPoint::to_string(sample->type).c_str(), color_new_point.c_str()); + svg.draw(support->point, color_new_point, config.head_radius); + svg.draw_text(support->point + Point(config.head_radius, 0), + SupportIslandPoint::to_string(support->type).c_str(), color_new_point.c_str() + ); #endif // SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG_PATH } @@ -640,7 +641,7 @@ using ThinParts = std::vector; /// struct ThickPart { - // neighbor from thick part (twin of first end) + // neighbor from thick part (twin of end with smallest source line index) // edge from thin to thick, start.node is inside of thick part const Neighbor* start; @@ -1099,45 +1100,39 @@ void draw(SVG &svg, const Field &field, const ExPolygon& border, bool draw_borde } #endif // SLA_SAMPLE_ISLAND_UTILS_STORE_FIELD_TO_SVG_PATH || SLA_SAMPLE_ISLAND_UTILS_STORE_PENINSULA_FIELD_TO_SVG_PATH +std::map create_wide_tiny_changes(const Positions& part_ends, const Lines &lines) { + std::map wide_tiny_changes; + // part_ends are already oriented + for (const Position &position : part_ends) { + Point p1, p2; + std::tie(p2, p1) = VoronoiGraphUtils::point_on_lines(position, lines); + const VD::edge_type *edge = position.neighbor->edge; + size_t i1 = edge->twin()->cell()->source_index(); + size_t i2 = edge->cell()->source_index(); + + // add sorted change from wide to tiny + // stored uder line index or line shorten in point b + WideTinyChange change(p1, p2, i2); + auto item = wide_tiny_changes.find(i1); + if (item == wide_tiny_changes.end()) { + wide_tiny_changes[i1] = {change}; + } else { + WideTinyChange::SortFromAToB pred(lines[i1]); + VectorUtils::insert_sorted(item->second, change, pred); + } + } + return wide_tiny_changes; +} + // IMPROVE do not use pointers on node but pointers on Neighbor Field create_thick_field(const ThickPart& part, const Lines &lines, const SampleConfig &config) { // store shortening of outline segments // line index, vector - std::map wide_tiny_changes; - for (const Position &position : part.ends) { - Point p1, p2; - std::tie(p1, p2) = VoronoiGraphUtils::point_on_lines(position, lines); - const VD::edge_type *edge = position.neighbor->edge; - size_t i1 = edge->cell()->source_index(); - size_t i2 = edge->twin()->cell()->source_index(); - - // function to add sorted change from wide to tiny - // stored uder line index or line shorten in point b - auto add = [&wide_tiny_changes, &lines](const Point &p1, const Point &p2, size_t i1, size_t i2) { - WideTinyChange change(p1, p2, i2); - auto item = wide_tiny_changes.find(i1); - if (item == wide_tiny_changes.end()) { - wide_tiny_changes[i1] = {change}; - } else { - WideTinyChange::SortFromAToB pred(lines[i1]); - VectorUtils::insert_sorted(item->second, change, pred); - } - }; - - const Line &l1 = lines[i1]; - if (VoronoiGraphUtils::is_opposit_direction(edge, l1)) { - // line1 is shorten on side line1.a --> line2 is shorten on side line2.b - add(p2, p1, i2, i1); - } else { - // line1 is shorten on side line1.b - add(p1, p2, i1, i2); - } - } + std::map wide_tiny_changes = create_wide_tiny_changes(part.ends, lines); // connection of line on island - std::map b_connection = - LineUtils::create_line_connection_over_b(lines); + std::map b_connection = LineUtils::create_line_connection_over_b(lines); std::vector source_indices; auto inser_point_b = [&lines, &b_connection, &source_indices] @@ -2240,6 +2235,27 @@ ThinPart create_only_thin_part(const VoronoiGraph::ExPath &path) { return ThinPart{*path_center_opt, /*ends*/ {}}; } +const VoronoiGraph::Node::Neighbor *get_smallest_source_index(const Positions& positions){ + // do not call with empty positions + assert(!positions.empty()); + if (positions.size() == 1) + return positions.front().neighbor; + + const VoronoiGraph::Node::Neighbor *smallest = nullptr; + size_t smallest_index = std::numeric_limits::max(); + for (const Position &position : positions) { + const VD::edge_type *e = position.neighbor->edge; + size_t min_index = std::min( + e->cell()->source_index(), + e->twin()->cell()->source_index()); + if (smallest_index > min_index) { + smallest_index = min_index; + smallest = position.neighbor; + } + } + return smallest; +} + std::pair convert_island_parts_to_thin_thick( const IslandParts& island_parts, const VoronoiGraph::ExPath &path) { @@ -2273,8 +2289,9 @@ std::pair convert_island_parts_to_thin_thick( thin_parts.push_back(ThinPart{center, std::move(ends)}); } else { assert(i.type == IslandPartType::thick); - //const Neighbor* start = polygon_index.changes.front().position.neighbor; - const Neighbor *start = VoronoiGraphUtils::get_twin(*ends.front().neighbor); + const Neighbor *start = VoronoiGraphUtils::get_twin(*get_smallest_source_index(ends)); + // NOTE: VD could contain different order of edges each run. + // To unify behavior as a start index is selected edge with smallest index of source line thick_parts.push_back(ThickPart {start, std::move(ends)}); } } diff --git a/tests/sla_print/sla_supptgen_tests.cpp b/tests/sla_print/sla_supptgen_tests.cpp index 1cd1e2be90..e5125ce022 100644 --- a/tests/sla_print/sla_supptgen_tests.cpp +++ b/tests/sla_print/sla_supptgen_tests.cpp @@ -19,6 +19,7 @@ using namespace Slic3r; using namespace Slic3r::sla; //#define STORE_SAMPLE_INTO_SVG_FILES "C:/data/temp/test_islands/sample_" +//#define STORE_ISLAND_ISSUES "C:/data/temp/issues/" TEST_CASE("Overhanging point should be supported", "[SupGen]") { @@ -69,9 +70,6 @@ TEST_CASE("Overhanging horizontal surface should be supported", "[SupGen]") { mesh.translate(0., 0., 5.); // lift up // mesh.WriteOBJFile("Cuboid.obj"); sla::SupportPoints pts = calc_support_pts(mesh); - - double mm2 = width * depth; - REQUIRE(!pts.empty()); } @@ -325,7 +323,7 @@ ExPolygon load_svg(const std::string& svg_filepath) { auto to_polygon = [](NSVGpath *path) { Polygon r; r.points.reserve(path->npts); - for (size_t i = 0; i < path->npts; i++) + for (int i = 0; i < path->npts; i++) r.points.push_back(Point(path->pts[2 * i], path->pts[2 * i + 1])); return r; }; @@ -455,10 +453,9 @@ SupportIslandPoints test_island_sampling(const ExPolygon & island, auto points = uniform_support_island(island, {}, config); Points chck_points = rasterize(island, config.head_radius); // TODO: Use resolution of printer - bool is_ok = true; - double max_distance = config.thick_inner_max_distance; - std::vector point_distances(chck_points.size(), - {max_distance + 1}); + bool is_island_supported = true; // Check rasterized island points that exist support point in max_distance + double max_distance = config.thick_inner_max_distance; + std::vector point_distances(chck_points.size(), {max_distance + 1}); for (size_t index = 0; index < chck_points.size(); ++index) { const Point &chck_point = chck_points[index]; double &min_distance = point_distances[index]; @@ -473,20 +470,26 @@ SupportIslandPoints test_island_sampling(const ExPolygon & island, if (min_distance > distance) { min_distance = distance; exist_close_support_point = true; - }; + } } } - if (!exist_close_support_point) is_ok = false; + if (!exist_close_support_point) is_island_supported = false; } - if (!is_ok) { // visualize - static int counter = 0; + bool is_all_points_inside_island = true; + for (const auto &point : points) + if (!island.contains(point->point)) + is_all_points_inside_island = false; + +#ifdef STORE_ISLAND_ISSUES + if (!is_island_supported || !is_all_points_inside_island) { // visualize + static int counter = 0; BoundingBox bb; for (const Point &pt : island.contour.points) bb.merge(pt); - SVG svg("Error" + std::to_string(++counter) + ".svg", bb); + SVG svg(STORE_ISLAND_ISSUES + std::string("Error") + std::to_string(++counter) + ".svg", bb); svg.draw(island, "blue", 0.5f); for (auto& p : points) - svg.draw(p->point, "lightgreen", config.head_radius); + svg.draw(p->point, island.contains(p->point) ? "lightgreen" : "red", config.head_radius); for (size_t index = 0; index < chck_points.size(); ++index) { const Point &chck_point = chck_points[index]; double distance = point_distances[index]; @@ -495,12 +498,12 @@ SupportIslandPoints test_island_sampling(const ExPolygon & island, svg.draw(chck_point, color, config.head_radius / 4); } } - CHECK(!points.empty()); - // TODO: solve issue - //CHECK(is_ok); +#endif // STORE_ISLAND_ISSUES + + CHECK(!points.empty()); + CHECK(is_all_points_inside_island); + // CHECK(is_island_supported); // TODO: skip special cases with one point and 2 points - // all points must be inside of island - for (const auto &point : points) { CHECK(island.contains(point->point)); } return points; } @@ -557,6 +560,7 @@ void store_sample(const SupportIslandPoints &samples, const ExPolygon &island) { /// TEST_CASE("Uniform sample test islands", "[SupGen], [VoronoiSkeleton]") { + //set_logging_level(5); float head_diameter = .4f; SampleConfig cfg = SampleConfigFactory::create(head_diameter); //cfg.path = "C:/data/temp/islands/<>.svg"; @@ -589,6 +593,9 @@ TEST_CASE("Disable visualization", "[hide]") #ifdef STORE_SAMPLE_INTO_SVG_FILES CHECK(false); #endif // STORE_SAMPLE_INTO_SVG_FILES +#ifdef STORE_ISLAND_ISSUES + CHECK(false); +#endif // STORE_ISLAND_ISSUES CHECK(is_uniform_support_island_visualization_disabled()); }