diff --git a/src/libslic3r/SLA/SupportIslands/ParabolaUtils.cpp b/src/libslic3r/SLA/SupportIslands/ParabolaUtils.cpp index 6dbca2cad2..5ea5b9816f 100644 --- a/src/libslic3r/SLA/SupportIslands/ParabolaUtils.cpp +++ b/src/libslic3r/SLA/SupportIslands/ParabolaUtils.cpp @@ -1,5 +1,5 @@ #include "ParabolaUtils.hpp" - +#include "PointUtils.hpp" using namespace Slic3r::sla; double ParabolaUtils::length(const ParabolaSegment ¶bola) @@ -79,6 +79,8 @@ void ParabolaUtils::draw(SVG & svg, double discretization_step) { using VD = Slic3r::Geometry::VoronoiDiagram; + if (PointUtils::is_equal(parabola.from, parabola.to)) return; + std::vector parabola_samples( {parabola.from, parabola.to}); diff --git a/src/libslic3r/SLA/SupportIslands/SampleConfigFactory.hpp b/src/libslic3r/SLA/SupportIslands/SampleConfigFactory.hpp index 5eed026486..262ef9fc03 100644 --- a/src/libslic3r/SLA/SupportIslands/SampleConfigFactory.hpp +++ b/src/libslic3r/SLA/SupportIslands/SampleConfigFactory.hpp @@ -16,54 +16,61 @@ public: // factory method to iniciate config static SampleConfig create(const SupportPointGenerator::Config &config) { + coord_t head_diameter = scale_(config.head_diameter); + coord_t min_distance = scale_(config.minimal_distance); + coord_t max_distance = 3 * min_distance; + coord_t sample_multiplicator = 10; // allign is made by selecting from samples + + // TODO: find valid params !!!! SampleConfig result; - result.max_distance = 100 * config.head_diameter; + result.max_distance = max_distance / sample_multiplicator; result.half_distance = result.max_distance / 2; - result.head_radius = config.head_diameter / 2; - result.minimal_distance_from_outline = config.head_diameter / 2.; + result.head_radius = head_diameter / 2; + result.minimal_distance_from_outline = head_diameter / 2.; result.minimal_support_distance = result.minimal_distance_from_outline + result.half_distance; result.max_length_for_one_support_point = 2 * result.minimal_distance_from_outline + - config.head_diameter; + head_diameter; coord_t max_length_for_one_support_point = - 2 * result.max_distance + - config.head_diameter + + 2 * max_distance + + head_diameter + 2 * result.minimal_distance_from_outline; if (result.max_length_for_one_support_point > max_length_for_one_support_point) result.max_length_for_one_support_point = max_length_for_one_support_point; coord_t min_length_for_one_support_point = - 2 * config.head_diameter + + 2 * head_diameter + 2 * result.minimal_distance_from_outline; if (result.max_length_for_one_support_point < min_length_for_one_support_point) result.max_length_for_one_support_point = min_length_for_one_support_point; result.max_length_for_two_support_points = - 2 * result.max_distance + 2 * config.head_diameter + + 2 * max_distance + 2 * head_diameter + 2 * result.minimal_distance_from_outline; coord_t max_length_for_two_support_points = - 2 * result.max_distance + - 2 * config.head_diameter + + 2 * max_distance + + 2 * head_diameter + 2 * result.minimal_distance_from_outline; if (result.max_length_for_two_support_points > max_length_for_two_support_points) result.max_length_for_two_support_points = max_length_for_two_support_points; - assert(result.max_length_for_two_support_points < result.max_length_for_one_support_point); + assert(result.max_length_for_two_support_points > result.max_length_for_one_support_point); - result.max_width_for_center_support_line = 2 * config.head_diameter; - coord_t min_width_for_center_support_line = - config.head_diameter + 2 * result.minimal_distance_from_outline; + result.max_width_for_center_support_line = + 2 * head_diameter + 2 * result.minimal_distance_from_outline + + max_distance / 2; + coord_t min_width_for_center_support_line = head_diameter + 2 * result.minimal_distance_from_outline; if (result.max_width_for_center_support_line < min_width_for_center_support_line) result.max_width_for_center_support_line = min_width_for_center_support_line; - coord_t max_width_for_center_support_line = 2 * result.max_distance + config.head_diameter; + coord_t max_width_for_center_support_line = 2 * max_distance + head_diameter; if (result.max_width_for_center_support_line > max_width_for_center_support_line) result.max_width_for_center_support_line = max_width_for_center_support_line; - result.min_width_for_outline_support = result.max_width_for_center_support_line - 2 * config.head_diameter; - assert(result.min_width_for_outline_support >= result.max_width_for_center_support_line); + result.min_width_for_outline_support = result.max_width_for_center_support_line - 2 * head_diameter; + assert(result.min_width_for_outline_support <= result.max_width_for_center_support_line); - result.outline_sample_distance = result.max_distance; + result.outline_sample_distance = result.max_distance/20; // Align support points // TODO: propagate print resolution diff --git a/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.cpp b/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.cpp index 7779f410ef..d96e706a90 100644 --- a/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.cpp +++ b/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.cpp @@ -16,11 +16,14 @@ #include // allign +#include "libslic3r/SLA/SupportPointGenerator.hpp" + // comment definition of NDEBUG to enable assert() //#define NDEBUG -#define SLA_SAMPLING_STORE_FIELD_TO_SVG -#define SLA_SAMPLING_STORE_VORONOI_GRAPH_TO_SVG +//#define SLA_SAMPLING_STORE_VORONOI_GRAPH_TO_SVG +//#define SLA_SAMPLING_STORE_FIELD_TO_SVG +//#define SLA_SAMPLING_STORE_POISSON_SAMPLING_TO_SVG #include @@ -28,6 +31,27 @@ using namespace Slic3r::sla; std::vector SampleIslandUtils::sample_expolygon( const ExPolygon &expoly, float samples_per_mm2) +{ + 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))); + + Points points = sample_expolygon(expoly, triangle_side); + + std::vector result; + result.reserve(points.size()); + std::transform(points.begin(), points.end(), std::back_inserter(result), + [](const Point &p) { return unscale(p).cast(); }); + + return result; +} + +Slic3r::Points SampleIslandUtils::sample_expolygon(const ExPolygon &expoly, + coord_t triangle_side) { const Points &points = expoly.contour.points; assert(!points.empty()); @@ -41,51 +65,45 @@ std::vector SampleIslandUtils::sample_expolygon( 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; + 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)); + 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 + // remove lines paralel with axe x lines.erase(std::remove_if(lines.begin(), lines.end(), [](const Line &l) { return l.a.y() == l.b.y(); - }), - lines.end()); + }), 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); - + // IMPROVE: guess size and reserve points + Points result; + size_t start_index = 0; 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) { + bool increase_start_index = true; + for (auto line = std::begin(lines)+start_index; line != std::end(lines); ++line) { const Point &b = line->b; if (b.y() <= y) { - // line = lines.erase(line); + // removing lines is slow, start index is faster + // line = lines.erase(line); + if (increase_start_index) ++start_index; continue; } + increase_start_index = false; const Point &a = line->a; if (a.y() >= y) break; float y_range = static_cast(b.y() - a.y()); @@ -106,12 +124,12 @@ std::vector SampleIslandUtils::sample_expolygon( coord_t x = div * triangle_side; if (is_odd) x -= triangle_side_2; while (x < end_x) { - out.push_back(unscale(x, y).cast()); + result.emplace_back(x, y); x += triangle_side; } } } - return out; + return result; } std::unique_ptr SampleIslandUtils::create_point( @@ -224,7 +242,14 @@ SupportIslandPoints SampleIslandUtils::sample_side_branch( distance -= neighbor->length(); prev_node = node; } - assert(fabs(distance - (sample_distance - cfg.side_distance)) < 1e-5); + //if (cfg.side_distance > sample_distance) { + // int count = static_cast(std::floor(cfg.side_distance / sample_distance)); + // for (int i = 0; i < count; ++i) { + // distance += sample_distance; + // result.pop_back(); + // } + //} + //assert(fabs(distance - (sample_distance - cfg.side_distance)) < 1e-5); result.back()->type = SupportIslandPoint::Type::center_line_end; return std::move(result); } @@ -777,8 +802,7 @@ SupportIslandPoints SampleIslandUtils::sample_expath( center_starts.pop(); for (const CenterStart &start : new_starts) center_starts.push(start); if (field_start.has_value()){ // exist new field start? - sample_field(field_start.value(), points, center_starts, done, lines, config); - field_start = {}; + sample_field(*field_start, points, center_starts, done, lines, config); } } return points; @@ -795,7 +819,23 @@ void SampleIslandUtils::sample_field(VoronoiGraph::Position &field_start, SupportIslandPoints outline_support = sample_outline(field, config); points.insert(points.end(), std::move_iterator(outline_support.begin()), std::move_iterator(outline_support.end())); - // TODO: sample field inside + + // Erode island to not sampled island around border, + // minimal value must be -config.minimal_distance_from_outline + Polygons polygons = offset(field.border, -2.f * config.minimal_distance_from_outline, + ClipperLib::jtSquare); + if (polygons.empty()) return; + ExPolygon inner(polygons.front()); + for (size_t i = 1; i < polygons.size(); ++i) { + Polygon &hole = polygons[i]; + inner.holes.push_back(hole); + } + Points inner_points = sample_expolygon(inner, config.max_distance); + std::transform(inner_points.begin(), inner_points.end(), std::back_inserter(points), + [](const Point &point) { + return std::make_unique( + point, SupportIslandPoint::Type::inner); + }); } std::vector SampleIslandUtils::sample_center( @@ -919,6 +959,7 @@ SampleIslandUtils::Field SampleIslandUtils::create_field( // line index, vector std::map wide_tiny_changes; + coord_t minimal_edge_length = std::max(config.max_distance / 2, 2*config.minimal_distance_from_outline); // cut lines at place where neighbor has width = min_width_for_outline_support // neighbor must be in direction from wide part to tiny part of island auto add_wide_tiny_change = @@ -929,7 +970,7 @@ SampleIslandUtils::Field SampleIslandUtils::create_field( // IMPROVE: check not only one neighbor but all path to edge coord_t rest_size = static_cast(neighbor->length() * (1. - position.ratio)); if (VoronoiGraphUtils::is_last_neighbor(neighbor) && - rest_size <= config.max_distance / 2) + rest_size <= minimal_edge_length) return false; // no change only rich outline // function to add sorted change from wide to tiny @@ -968,16 +1009,19 @@ SampleIslandUtils::Field SampleIslandUtils::create_field( return true; }; - const VoronoiGraph::Node::Neighbor *neighbor = field_start.neighbor; - const VoronoiGraph::Node::Neighbor *twin_neighbor = VoronoiGraphUtils::get_twin(neighbor); - VoronoiGraph::Position position(twin_neighbor, 1. - field_start.ratio); - add_wide_tiny_change(position, neighbor->node); + const VoronoiGraph::Node::Neighbor *tiny_wide_neighbor = field_start.neighbor; + const VoronoiGraph::Node::Neighbor *wide_tiny_neighbor = VoronoiGraphUtils::get_twin(tiny_wide_neighbor); + VoronoiGraph::Position position(wide_tiny_neighbor, 1. - field_start.ratio); + add_wide_tiny_change(position, tiny_wide_neighbor->node); std::set done; - done.insert(twin_neighbor->node); + done.insert(wide_tiny_neighbor->node); + // prev node , node using ProcessItem = std::pair; + // initial proccess item from tiny part to wide part of island + ProcessItem start(wide_tiny_neighbor->node, tiny_wide_neighbor->node); std::queue process; - process.push({twin_neighbor->node, neighbor->node}); + process.push(start); // all lines belongs to polygon std::set field_line_indexes; @@ -1051,6 +1095,14 @@ SampleIslandUtils::Field SampleIslandUtils::create_field( } } if (no_change) break; + + // Field ends with change into first index + if (!is_first && change_item->first == input_index && + change_index == 0) { + return false; + } else { + is_first = false; + } } const WideTinyChange &change = changes[change_index]; // prevent double points @@ -1069,8 +1121,6 @@ SampleIslandUtils::Field SampleIslandUtils::create_field( } done.insert(index); index = change.next_line_index; - // end of conture - if (!is_first && index == input_index) return false; change_item = wide_tiny_changes.find(index); } return true; @@ -1080,8 +1130,8 @@ SampleIslandUtils::Field SampleIslandUtils::create_field( points.reserve(field_line_indexes.size()); std::vector outline_indexes; outline_indexes.reserve(field_line_indexes.size()); - size_t input_index1 = neighbor->edge->cell()->source_index(); - size_t input_index2 = neighbor->edge->twin()->cell()->source_index(); + size_t input_index1 = tiny_wide_neighbor->edge->cell()->source_index(); + size_t input_index2 = tiny_wide_neighbor->edge->twin()->cell()->source_index(); size_t input_index = std::min(input_index1, input_index2); size_t outline_index = input_index; std::set done_indexes; @@ -1129,6 +1179,16 @@ SampleIslandUtils::Field SampleIslandUtils::create_field( SupportIslandPoints SampleIslandUtils::sample_outline( const Field &field, const SampleConfig &config) { + // TODO: fix it by neighbor line angles + // Do not create inner expoly and test all points to lay inside + Polygons polygons = offset(field.border,-config.minimal_distance_from_outline + 5, ClipperLib::jtSquare); + if (polygons.empty()) return {}; // no place for support point + ExPolygon inner(polygons.front()); + for (size_t i = 1; i < polygons.size(); ++i) { + Polygon &hole = polygons[i]; + inner.holes.push_back(hole); + } + coord_t sample_distance = config.outline_sample_distance; coord_t outline_distance = config.minimal_distance_from_outline; SupportIslandPoints result; @@ -1143,8 +1203,13 @@ SupportIslandPoints SampleIslandUtils::sample_outline( do { double ratio = (sample_distance - last_support) / line_length_double; Point point = line.a + dir * ratio + move_from_outline; - result.emplace_back(std::make_unique( - point, source_index, SupportIslandPoint::Type::outline)); + + // TODO: improve prevent sampling out of field near sharp corner + // use range for possible ratio + if (inner.contains(point)) + result.emplace_back(std::make_unique( + point, source_index, SupportIslandPoint::Type::outline)); + last_support -= sample_distance; } while (last_support + line_length > sample_distance); } diff --git a/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.hpp b/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.hpp index ee6794c3af..b7d77196d5 100644 --- a/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.hpp +++ b/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.hpp @@ -32,6 +32,14 @@ public: /// Samples - 2d unscaled coordinates [in mm] static std::vector sample_expolygon(const ExPolygon &expoly, float samples_per_mm2); + /// + /// Uniform sample expolygon area by points inside Equilateral triangle center + /// + /// Input area to sample.(scaled) + /// Distance between samples. + /// Uniform samples(scaled) + static Points sample_expolygon(const ExPolygon &expoly, coord_t triangle_side); + /// /// Create support point on edge defined by neighbor /// diff --git a/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.cpp b/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.cpp index d12e2f8028..a43d4603e4 100644 --- a/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.cpp +++ b/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.cpp @@ -7,6 +7,39 @@ SupportIslandPoint::SupportIslandPoint(Slic3r::Point point, Type type) : point(std::move(point)), type(type) {} +bool SupportIslandPoint::can_move(const Type &type) +{ + // use shorter list + /* + static const std::set can_move({ + Type::center_line, + Type::center_circle, + Type::center_circle_end, + Type::center_circle_end2, + Type::outline, + Type::inner + }); + return can_move.find(type) != can_move.end(); + /*/ // switch comment center + static const std::set cant_move({ + Type::one_center_point, + Type::two_points, + Type::center_line_end, + Type::center_line_end2, + Type::center_line_end3, + Type::center_line_start + }); + return cant_move.find(type) == cant_move.end(); + //*/ +} + +bool SupportIslandPoint::can_move() const { return can_move(type); } + +SupportCenterIslandPoint::SupportCenterIslandPoint( + Point point, VoronoiGraph::Position position, Type type) + : SupportIslandPoint(point, type), position(position) +{} + coord_t SupportIslandPoint::move(const Point &destination) { Point diff = destination - point; diff --git a/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.hpp b/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.hpp index ff5968625f..1c7685ea48 100644 --- a/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.hpp +++ b/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.hpp @@ -11,8 +11,9 @@ namespace Slic3r::sla { /// /// DTO position with information about source of support point /// -struct SupportIslandPoint +class SupportIslandPoint { +public: enum class Type: unsigned char { one_center_point, two_points, @@ -26,41 +27,41 @@ struct SupportIslandPoint // need allign) center_circle_end2, // circle finish by multi points (one end per // circle - need allign) - outline, // keep position align with island outline + inner, // point inside wide part, without restriction on move + undefined }; - Type type; - Slic3r::Point point; // 2 coordinate point in a layer (in one slice) + Type type; + Point point; - //SupportIslandPoint() : point(0, 0), type(Type::undefined) {} - SupportIslandPoint(Slic3r::Point point, Type type = Type::undefined); +public: + /// + /// constructor + /// + /// coordinate point inside a layer (in one slice) + /// type of support point + SupportIslandPoint(Point point, Type type = Type::undefined); + + /// + /// virtual destructor to be inheritable + /// virtual ~SupportIslandPoint() = default; - static bool can_move(const Type &type) - { - // use shorter list - /* - static const std::set can_move({ - Type::center_line, - Type::center_circle, - Type::center_circle_end, - Type::center_circle_end2}); - return can_move.find(type) != can_move.end(); - /*/ // switch comment center - static const std::set cant_move({ - Type::one_center_point, - Type::two_points, - Type::center_line_end, - Type::center_line_end2, - Type::center_line_end3, - Type::center_line_start}); - return cant_move.find(type) == cant_move.end(); - //*/ - } - - virtual bool can_move() const { return can_move(type); } + /// + /// static function to decide if type is possible to move or not + /// + /// type to distinguish + /// True when is possible to move, otherwise FALSE + static bool can_move(const Type &type); + + /// + /// static function to decide if type is possible to move or not + /// + /// type to distinguish + /// True when is possible to move, otherwise FALSE + virtual bool can_move() const; /// /// Move position of support point close to destination @@ -74,8 +75,13 @@ struct SupportIslandPoint using SupportIslandPointPtr = std::unique_ptr; using SupportIslandPoints = std::vector; -struct SupportCenterIslandPoint : public SupportIslandPoint +/// +/// DTO Support point laying on voronoi graph edge +/// Restriction to move only on Voronoi graph +/// +class SupportCenterIslandPoint : public SupportIslandPoint { +public: // Define position on voronoi graph // Lose data when voronoi graph does NOT exist VoronoiGraph::Position position; @@ -85,20 +91,26 @@ struct SupportCenterIslandPoint : public SupportIslandPoint // TODO: should earn when created const double max_distance = 1e6; // [in nm] --> 1 mm - SupportCenterIslandPoint(Slic3r::Point point, +public: + SupportCenterIslandPoint(Point point, VoronoiGraph::Position position, - Type type = Type::center_line) - : SupportIslandPoint(point, type), position(position) - {} - + Type type = Type::center_line); + bool can_move() const override{ return true; } coord_t move(const Point &destination) override; }; -struct SupportOutlineIslandPoint : public SupportIslandPoint +/// +/// DTO Support point laying on Outline of island +/// Restriction to move only on outline +/// +class SupportOutlineIslandPoint : public SupportIslandPoint { +public: // index of line form island outline size_t index; + +public: SupportOutlineIslandPoint(Slic3r::Point point, size_t index, Type type = Type::outline) diff --git a/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.hpp b/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.hpp index 143158d06a..0de5a0b89d 100644 --- a/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.hpp +++ b/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.hpp @@ -381,7 +381,7 @@ public: const Lines & lines); /// - /// calculate both point on source lines correspond to edge postion + /// Calculate both point on source lines correspond to edge postion /// Faster way to get both point_on_line /// /// Position on edge diff --git a/tests/sla_print/sla_supptgen_tests.cpp b/tests/sla_print/sla_supptgen_tests.cpp index 8aa92d6965..b701e267cc 100644 --- a/tests/sla_print/sla_supptgen_tests.cpp +++ b/tests/sla_print/sla_supptgen_tests.cpp @@ -546,9 +546,16 @@ TEST_CASE("speed sampling", "[SupGen]") { TEST_CASE("Small islands should be supported in center", "[SupGen][VoronoiSkeleton]") { - double size = 3e7; + double size = 3e7; SampleConfig cfg = create_sample_config(size); ExPolygons islands = createTestIslands(size); + + // TODO: remove next 3 lines, debug sharp triangle + auto triangle = PolygonUtils::create_isosceles_triangle(8. * size, 40. * size); + islands = {ExPolygon(triangle)}; + auto test_island = create_tiny_wide_test_2(3 * size, 2 / 3. * size); + islands = {test_island}; + for (ExPolygon &island : islands) { size_t debug_index = &island - &islands.front(); auto points = test_island_sampling(island, cfg); @@ -561,3 +568,109 @@ TEST_CASE("Small islands should be supported in center", "[SupGen][VoronoiSkelet // points should be equal to pointsR } } + +std::vector sample_old(const ExPolygon &island) +{ + // Create the support point generator + static TriangleMesh mesh; + static sla::IndexedMesh emesh{mesh}; + static sla::SupportPointGenerator::Config autogencfg; + //autogencfg.minimal_distance = 8.f; + static sla::SupportPointGenerator generator{emesh, autogencfg, [] {}, [](int) {}}; + + // tear preasure + float tp = autogencfg.tear_pressure(); + size_t layer_id = 13; + coordf_t print_z = 11.f; + SupportPointGenerator::MyLayer layer(layer_id, print_z); + ExPolygon poly = island; + BoundingBox bbox(island); + Vec2f centroid; + float area = island.area(); + float h = 17.f; + sla::SupportPointGenerator::Structure s(layer, poly, bbox, centroid,area,h); + auto flag = sla::SupportPointGenerator::IslandCoverageFlags( + sla::SupportPointGenerator::icfIsNew | sla::SupportPointGenerator::icfWithBoundary); + SupportPointGenerator::PointGrid3D grid3d; + generator.uniformly_cover({island}, s, s.area * tp, grid3d, flag); + + std::vector result; + result.reserve(grid3d.grid.size()); + for (auto g : grid3d.grid) { + const Vec3f &p = g.second.position; + Vec2f p2f(p.x(), p.y()); + result.emplace_back(scale_(p2f)); + } + return result; +} + +#include +std::vector sample_filip(const ExPolygon &island) +{ + static SampleConfig cfg = create_sample_config(1e6); + SupportIslandPoints points = SupportPointGenerator::uniform_cover_island(island, cfg); + + std::vector result; + result.reserve(points.size()); + for (auto &p : points) { + result.push_back(p->point.cast()); + } + return result; +} + +void store_sample(const std::vector &samples, const ExPolygon& island) +{ + static int counter = 0; + BoundingBox bb(island); + SVG svg(("sample_"+std::to_string(counter++)+".svg").c_str(), bb); + + double mm = scale_(1); + svg.draw(island, "lightgray"); + for (const auto &s : samples) { + svg.draw(s.cast(), "blue", 0.2*mm); + } + + // draw resolution + Point p(bb.min.x() + 1e6, bb.max.y() - 2e6); + svg.draw_text(p, (std::to_string(samples.size()) + " samples").c_str(), "black"); + svg.draw_text(p - Point(0., 1.8e6), "Scale 1 cm ", "black"); + Point start = p - Point(0., 2.3e6); + svg.draw(Line(start + Point(0., 5e5), start + Point(10*mm, 5e5)), "black", 2e5); + svg.draw(Line(start + Point(0., -5e5), start + Point(10*mm, -5e5)), "black", 2e5); + svg.draw(Line(start + Point(10*mm, 5e5), start + Point(10*mm, -5e5)), "black", 2e5); + for (int i=0; i<10;i+=2) + svg.draw(Line(start + Point(i*mm, 0.), start + Point((i+1)*mm, 0.)), "black", 1e6); +} + +TEST_CASE("Compare sampling test") +{ + enum class Sampling { + old, + filip + } sample_type = Sampling::old; + + std::function(const ExPolygon &)> sample = + (sample_type == Sampling::old) ? sample_old : + (sample_type == Sampling::filip) ? sample_filip : + nullptr; + + double size1 = 1e6; + double size2 = 3e6; + ExPolygons islands = createTestIslands(1e6); + ExPolygons islands_big = createTestIslands(3e6); + islands.insert(islands.end(), islands_big.begin(), islands_big.end()); + + islands = {ExPolygon(PolygonUtils::create_rect(size1 / 2, size1))}; + + for (ExPolygon &island : islands) { + size_t debug_index = &island - &islands.front(); + auto samples = sample(island); + store_sample(samples, island); + + double angle = 3.14 / 3; // cca 60 degree + island.rotate(angle); + samples = sample(island); + store_sample(samples, island); + } +} +