Add uniform sampling of ExPolygon

This commit is contained in:
Filip Sykala 2021-04-15 12:32:25 +02:00 committed by Lukas Matena
parent f44b0d51f1
commit b6ee9f4368
3 changed files with 148 additions and 4 deletions

View File

@ -26,6 +26,94 @@
using namespace Slic3r::sla;
std::vector<Slic3r::Vec2f> 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<coord_t>(
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<coord_t>(
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<Vec2f> 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<coord_t> 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<float>(b.y() - a.y());
float x_range = static_cast<float>(b.x() - a.x());
float ratio = (y - a.y()) / y_range;
coord_t intersection = a.x() +
static_cast<coord_t>(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<float>());
x += triangle_side;
}
}
}
return out;
}
std::unique_ptr<SupportIslandPoint> SampleIslandUtils::create_point(
const VoronoiGraph::Node::Neighbor *neighbor,
double ratio,

View File

@ -24,6 +24,14 @@ class SampleIslandUtils
public:
SampleIslandUtils() = delete;
/// <summary>
/// Uniform sample expolygon area by points inside Equilateral triangle center
/// </summary>
/// <param name="expoly">Input area to sample. (scaled)</param>
/// <param name="samples_per_mm2">Density of sampling.</param>
/// <returns>Samples - 2d unscaled coordinates [in mm]</returns>
static std::vector<Vec2f> sample_expolygon(const ExPolygon &expoly, float samples_per_mm2);
/// <summary>
/// Create support point on edge defined by neighbor
/// </summary>

View File

@ -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 <libslic3r/SLA/SupportPointGenerator.hpp>
#include <libslic3r/SLA/SupportIslands/LineUtils.hpp>
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<std::vector<Vec2f>> result1;
result1.reserve(islands.size()*count);
for (size_t i = 0; i<count; ++i)
for (const auto& island: islands)
result1.emplace_back(sample_expolygon(island, samples_per_mm2, m_rng));
std::vector<std::vector<Vec2f>> 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<coord_t>(), "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<coord_t>(), "green", 1e6);
}//*/
}
TEST_CASE("Small islands should be supported in center", "[SupGen][VoronoiSkeleton]")
{
double size = 3e7;