From faa778d349c688773124cacdd42f9eee6cd44453 Mon Sep 17 00:00:00 2001 From: Filip Sykala - NTB T15p Date: Tue, 4 Mar 2025 18:01:55 +0100 Subject: [PATCH] SPE-2709: Fix precision of calculation line cross for thick field creation purpose: Fixes freezing of SLA support point generator in certain cases --- .../SupportIslands/UniformSupportIsland.cpp | 33 +- .../SLA/SupportIslands/VoronoiGraphUtils.cpp | 13 +- tests/data/sla_islands/SPE-2709.svg | 1176 +++++++++++++++++ tests/sla_print/sla_supptgen_tests.cpp | 28 + 4 files changed, 1243 insertions(+), 7 deletions(-) create mode 100644 tests/data/sla_islands/SPE-2709.svg diff --git a/src/libslic3r/SLA/SupportIslands/UniformSupportIsland.cpp b/src/libslic3r/SLA/SupportIslands/UniformSupportIsland.cpp index 67793d04df..6ed9b51c09 100644 --- a/src/libslic3r/SLA/SupportIslands/UniformSupportIsland.cpp +++ b/src/libslic3r/SLA/SupportIslands/UniformSupportIsland.cpp @@ -1164,10 +1164,9 @@ Field create_thick_field(const ThickPart& part, const Lines &lines, const Sample assert(!changes.empty()); size_t change_index = 0; if (!points.empty()) { // Not first point, could lead to termination - const Point &last_point = points.back(); LineUtils::SortFromAToB pred(lines[index]); bool no_change = false; - while (pred.compare(changes[change_index].new_b, last_point)) { + while (pred.compare(changes[change_index].new_b, points.back())) { ++change_index; if (change_index >= changes.size()) { no_change = true; @@ -1244,13 +1243,39 @@ Field create_thick_field(const ThickPart& part, const Lines &lines, const Sample size_t outline_index = input_index; // Done indexes is used to detect holes in field std::set done_indices; // IMPROVE: use vector(size of lines count) with bools +#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_FIELD_TO_SVG_PATH + static int counter = 0; + std::string field_to_svg_path = replace_first( + SLA_SAMPLE_ISLAND_UTILS_STORE_FIELD_TO_SVG_PATH, "<>", std::to_string(counter++)); + { + SVG svg(field_to_svg_path.c_str(), LineUtils::create_bounding_box(lines)); + LineUtils::draw(svg, lines, "black", 0., /*indices*/ true); + for(const auto& change_it: wide_tiny_changes) + for (const auto& change: change_it.second){ + Line bisector(change.new_b, change.next_new_a); + LineUtils::draw(svg, bisector, "red"); + std::string text = "from " + std::to_string(change_it.first) + + " to " + std::to_string(change.next_line_index); + svg.draw_text(bisector.a/2 + bisector.b/2, text.c_str(), "orange"); + } + } // flush svg file +#endif // SLA_SAMPLE_ISLAND_UTILS_STORE_FIELD_TO_SVG_PATH do { if (!insert_changes(outline_index, points, done_indices, input_index)) break; inser_point_b(outline_index, points, done_indices); + + if (points.size() > (lines.size() + 2*part.ends.size())){ + // protection against endless loop + assert(false); + return {}; + } } while (outline_index != input_index); assert(points.size() >= 3); + if (points.size() < 3) + return {}; // invalid field + ExPolygon border{Polygon{points}}; // finding holes(another closed polygon) if (done_indices.size() < field_line_indices.size()) { @@ -1279,9 +1304,7 @@ Field create_thick_field(const ThickPart& part, const Lines &lines, const Sample bool draw_source_line_indexes = true; bool draw_border_line_indexes = false; bool draw_field_source_indexes = true; - static int counter = 0; - SVG svg(replace_first(SLA_SAMPLE_ISLAND_UTILS_STORE_FIELD_TO_SVG_PATH, - "<>", std::to_string(counter++)).c_str(),LineUtils::create_bounding_box(lines)); + SVG svg(field_to_svg_path.c_str(),LineUtils::create_bounding_box(lines)); LineUtils::draw(svg, lines, source_line_color, 0., draw_source_line_indexes); draw(svg, field, border, draw_border_line_indexes, draw_field_source_indexes); } diff --git a/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.cpp b/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.cpp index 78d89dbdec..5f4de94734 100644 --- a/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.cpp +++ b/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.cpp @@ -983,7 +983,7 @@ std::pair VoronoiGraphUtils::point_on_lines( //assert(edge->is_linear()); Point edge_point = create_edge_point(position); - auto point_on_line = [&](const VD::edge_type *edge) -> Point { + auto point_on_line = [&](const VD::edge_type *edge) -> Point { assert(edge->is_finite()); const VD::cell_type *cell = edge->cell(); size_t line_index = cell->source_index(); @@ -1000,7 +1000,16 @@ std::pair VoronoiGraphUtils::point_on_lines( Line intersecting_line(edge_point, edge_point + PointUtils::perp(dir)); std::optional intersection = LineUtils::intersection(line, intersecting_line); assert(intersection.has_value()); - return intersection->cast(); + Point result = intersection->cast(); + // result MUST lay on the line, accuracy of float intersection could move point out of line + coord_t tolerance = 5; // for sure it is 5 but found case which need tolerance(1) - SPE-2709 + if (abs(result.x() - line.a.x()) < tolerance && + abs(result.y() - line.a.y()) < tolerance) + return line.a; // almost point a + if (abs(result.x() - line.b.x()) < tolerance && + abs(result.y() - line.b.y()) < tolerance) + return line.b; // almost point b + return result; }; return {point_on_line(edge), point_on_line(edge->twin())}; diff --git a/tests/data/sla_islands/SPE-2709.svg b/tests/data/sla_islands/SPE-2709.svg new file mode 100644 index 0000000000..3b31bc56f3 --- /dev/null +++ b/tests/data/sla_islands/SPE-2709.svg @@ -0,0 +1,1176 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +thin_part_change +thin_part_change +thin_part_change +thin_part_change +thin_part_change +thin_part_change +thin_part_change +thin_part +thin_part_change +thin_part_change +thin_part_change +thin_part_change +thin_part_change +thin_part_change +thin_part_change +thin_part_change +thin_part_change +thin_part_change +thin_part +thin_part_change +thin_part +thick_part_outline +thick_part_outline +thick_part_outline +thick_part_outline +thick_part_outline +thick_part_outline +thick_part_outline +thick_part_outline +thick_part_outline +thick_part_outline +thick_part_outline +thick_part_outline +thick_part_outline +thick_part_outline +thick_part_outline +thick_part_outline +thick_part_outline +thick_part_outline +thick_part_outline +thick_part_outline +thick_part_inner +thick_part_inner +thick_part_inner +thick_part_inner +thick_part_inner +thick_part_inner diff --git a/tests/sla_print/sla_supptgen_tests.cpp b/tests/sla_print/sla_supptgen_tests.cpp index 962a71a177..62a7f8572f 100644 --- a/tests/sla_print/sla_supptgen_tests.cpp +++ b/tests/sla_print/sla_supptgen_tests.cpp @@ -587,6 +587,34 @@ TEST_CASE("Uniform sample test islands", "[SupGen], [VoronoiSkeleton]") } } +TEST_CASE("Sample island with config", "[SupportIsland]") { + // set_logging_level(5); + SampleConfig cfg{ + /*thin_max_distance*/ 5832568, + /*thick_inner_max_distance*/ 7290710, + /*thick_outline_max_distance*/ 5468032, + /*head_radius*/ 250000, + /*minimal_distance_from_outline*/ 250000, + /*maximal_distance_from_outline*/ 1944189, + /*max_length_for_one_support_point*/ 1869413, + /*max_length_for_two_support_points*/ 7290710, + /*max_length_ratio_for_two_support_points*/ 0.250000000f, + /*thin_max_width*/ 4673532, + /*thick_min_width*/ 4019237, + /*min_part_length*/ 5832568, + /*minimal_move*/ 100000, + /*count_iteration*/ 30, + /*max_align_distance*/ 3645355, + /*simplification_tolerance*/ 50000.000000000007 + //*path*/, "C:/data/temp/islands/<>.svg" // need define OPTION_TO_STORE_ISLAND in SampleConfig.hpp + }; + std::string dir = std::string(TEST_DATA_DIR PATH_SEPARATOR) + "sla_islands/"; + ExPolygon island = load_svg(dir + "SPE-2709.svg"); // Bad field creation + SupportIslandPoints points = test_island_sampling(island, cfg); + // in time of write poins.size() == 39 + CHECK(points.size() > 22); // not only thin parts +} + TEST_CASE("Disable visualization", "[hide]") { CHECK(true);