diff --git a/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.cpp b/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.cpp index 332816dbf3..7779f410ef 100644 --- a/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.cpp +++ b/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.cpp @@ -26,6 +26,94 @@ using namespace Slic3r::sla; +std::vector SampleIslandUtils::sample_expolygon( + const ExPolygon &expoly, float samples_per_mm2) +{ + const Points &points = expoly.contour.points; + assert(!points.empty()); + // get y range + coord_t min_y = points.front().y(); + coord_t max_y = min_y; + for (const Point &point : points) { + if (min_y > point.y()) + min_y = point.y(); + else if (max_y < point.y()) + max_y = point.y(); + } + + static const float mm2_area = scale_(1) * scale_(1); + // Equilateral triangle area = (side * height) / 2 + float triangle_area = mm2_area / samples_per_mm2; + // Triangle area = sqrt(3) / 4 * "triangle side" + static const float coef1 = sqrt(3.) / 4.; + coord_t triangle_side = static_cast( + std::round(sqrt(triangle_area * coef1))); + coord_t triangle_side_2 = triangle_side / 2; + static const float coef2 = sqrt(3.) / 2.; + coord_t triangle_height = static_cast( + std::round(triangle_side * coef2)); + + // IMPROVE: use line end y + Lines lines = to_lines(expoly); + // remove lines with y direction + lines.erase(std::remove_if(lines.begin(), lines.end(), + [](const Line &l) { + return l.a.y() == l.b.y(); + }), + lines.end()); + // change line direction from top to bottom + for (Line &line : lines) + if (line.a.y() > line.b.y()) std::swap(line.a, line.b); + // sort by a.y() + std::sort(lines.begin(), lines.end(), + [](const Line &l1, const Line &l2) -> bool { + return l1.a.y() < l2.a.y(); + }); + + std::vector out; + // size_t count_sample_lines = (max_y - min_y) / triangle_height; + // out.reserve(count_sample_lines * count_sample_lines); + + bool is_odd = false; + for (coord_t y = min_y + triangle_height / 2; y < max_y; + y += triangle_height) { + is_odd = !is_odd; + std::vector intersections; + + for (auto line = std::begin(lines); line != std::end(lines); ++line) { + const Point &b = line->b; + if (b.y() <= y) { + // line = lines.erase(line); + continue; + } + const Point &a = line->a; + if (a.y() >= y) break; + float y_range = static_cast(b.y() - a.y()); + float x_range = static_cast(b.x() - a.x()); + float ratio = (y - a.y()) / y_range; + coord_t intersection = a.x() + + static_cast(x_range * ratio); + intersections.push_back(intersection); + } + assert(intersections.size() % 2 == 0); + std::sort(intersections.begin(), intersections.end()); + for (size_t index = 0; index + 1 < intersections.size(); index += 2) { + coord_t start_x = intersections[index]; + coord_t end_x = intersections[index + 1]; + if (is_odd) start_x += triangle_side_2; + coord_t div = start_x / triangle_side; + if (start_x > 0) div += 1; + coord_t x = div * triangle_side; + if (is_odd) x -= triangle_side_2; + while (x < end_x) { + out.push_back(unscale(x, y).cast()); + x += triangle_side; + } + } + } + return out; +} + std::unique_ptr SampleIslandUtils::create_point( const VoronoiGraph::Node::Neighbor *neighbor, double ratio, diff --git a/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.hpp b/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.hpp index 72da95cf22..ee6794c3af 100644 --- a/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.hpp +++ b/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.hpp @@ -24,6 +24,14 @@ class SampleIslandUtils public: SampleIslandUtils() = delete; + /// + /// Uniform sample expolygon area by points inside Equilateral triangle center + /// + /// Input area to sample. (scaled) + /// Density of sampling. + /// Samples - 2d unscaled coordinates [in mm] + static std::vector sample_expolygon(const ExPolygon &expoly, float samples_per_mm2); + /// /// Create support point on edge defined by neighbor /// diff --git a/tests/sla_print/sla_supptgen_tests.cpp b/tests/sla_print/sla_supptgen_tests.cpp index a440834a63..8aa92d6965 100644 --- a/tests/sla_print/sla_supptgen_tests.cpp +++ b/tests/sla_print/sla_supptgen_tests.cpp @@ -158,10 +158,10 @@ Slic3r::Polygon create_cross_roads(double size, double width) ExPolygon create_trinagle_with_hole(double size) { - return ExPolygon(PolygonUtils::create_equilateral_triangle(size), - {{size / 4, size / 4}, - {size / 2, size / 2}, - {size / 2, size / 4}}); + auto hole = PolygonUtils::create_equilateral_triangle(size / 3); + hole.reverse(); + hole.rotate(3.14 / 4); + return ExPolygon(PolygonUtils::create_equilateral_triangle(size), hole); } ExPolygon create_square_with_hole(double size, double hole_size) @@ -496,6 +496,54 @@ TEST_CASE("Speed align", "[VoronoiSkeleton]") } } +//#include +#include +TEST_CASE("speed sampling", "[SupGen]") { + double size = 3e7; + float samples_per_mm2 = 0.01f; + ExPolygons islands = createTestIslands(size); + std::random_device rd; + std::mt19937 m_rng; + m_rng.seed(rd()); + + size_t count = 1; + + std::vector> result1; + result1.reserve(islands.size()*count); + for (size_t i = 0; i> result2; + result2.reserve(islands.size()*count); + for (size_t i = 0; i < count; ++i) + for (const auto &island : islands) + result2.emplace_back(SampleIslandUtils::sample_expolygon(island, samples_per_mm2)); //*/ + + /*size_t all = 0; + for (auto& result : result2) { + //std::cout << "case " << &result - &result1[0] << " points " << result.size() << std::endl; + all += result.size(); + } + std::cout << "All points " << all << std::endl;*/ + + for (size_t i = 0; i < result1.size(); ++i) { + size_t island_index = i % islands.size(); + ExPolygon &island = islands[island_index]; + + Lines lines = to_lines(island.contour); + std::string name = "sample_" + std::to_string(i) + ".svg"; + SVG svg(name, LineUtils::create_bounding_box(lines)); + svg.draw(island, "lightgray"); + svg.draw_text({0, 0}, ("random samples " + std::to_string(result1[i].size())).c_str(), "blue"); + for (Vec2f &p : result1[i]) + svg.draw((p * 1e6).cast(), "blue", 1e6); + svg.draw_text({0., 5e6}, ("uniform samples " + std::to_string(result2[i].size())).c_str(), "green"); + for (Vec2f &p : result2[i]) + svg.draw((p * 1e6).cast(), "green", 1e6); + }//*/ +} + TEST_CASE("Small islands should be supported in center", "[SupGen][VoronoiSkeleton]") { double size = 3e7;