mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-01 15:22:01 +08:00
Add uniform sampling of ExPolygon
This commit is contained in:
parent
f44b0d51f1
commit
b6ee9f4368
@ -26,6 +26,94 @@
|
|||||||
|
|
||||||
using namespace Slic3r::sla;
|
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(
|
std::unique_ptr<SupportIslandPoint> SampleIslandUtils::create_point(
|
||||||
const VoronoiGraph::Node::Neighbor *neighbor,
|
const VoronoiGraph::Node::Neighbor *neighbor,
|
||||||
double ratio,
|
double ratio,
|
||||||
|
@ -24,6 +24,14 @@ class SampleIslandUtils
|
|||||||
public:
|
public:
|
||||||
SampleIslandUtils() = delete;
|
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>
|
/// <summary>
|
||||||
/// Create support point on edge defined by neighbor
|
/// Create support point on edge defined by neighbor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -158,10 +158,10 @@ Slic3r::Polygon create_cross_roads(double size, double width)
|
|||||||
|
|
||||||
ExPolygon create_trinagle_with_hole(double size)
|
ExPolygon create_trinagle_with_hole(double size)
|
||||||
{
|
{
|
||||||
return ExPolygon(PolygonUtils::create_equilateral_triangle(size),
|
auto hole = PolygonUtils::create_equilateral_triangle(size / 3);
|
||||||
{{size / 4, size / 4},
|
hole.reverse();
|
||||||
{size / 2, size / 2},
|
hole.rotate(3.14 / 4);
|
||||||
{size / 2, size / 4}});
|
return ExPolygon(PolygonUtils::create_equilateral_triangle(size), hole);
|
||||||
}
|
}
|
||||||
|
|
||||||
ExPolygon create_square_with_hole(double size, double hole_size)
|
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]")
|
TEST_CASE("Small islands should be supported in center", "[SupGen][VoronoiSkeleton]")
|
||||||
{
|
{
|
||||||
double size = 3e7;
|
double size = 3e7;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user